Based on #401 - Seemed easier to port the relevant changes with some modifications than to fix merge conflicts and mess with history.
Co-Authored-By: stephaje <57157278+stephaje@users.noreply.github.com>
- Our own auth flow, removed 'plex-oauth' dep.
- Fixed normal registrations
- Combined login/register plex methods
- Changed login page plex btn styling
- Reverted colors on jellyfin/plex btns (couldn't find a nice one and it hurt me)
- Removed plex client id from server config, replaced by plex host and plex machine id config items
- Plex client id is generated on the client and stored for reuse, each client will do that instead of the server storing it for everyone.
- Use plex machine id to ensure only approved users can login via plex (users with access to host server library)
- Renamed some structs and funcs
- Removed background from plex icon
- Made buttons and inputs bigger (more padding, also unrelated to rest of changed but i think it looks nice)
Was being removed from config when set to false, then once the server restarts would be set back to default value (true).
Now is kept in config with value of false when turned off.
* dev workflow: Add arm64 platform build
in sequence because paralellising the jobs looks hard
* dev action: remove `dev` tag
I think it would be better to just refer to them with their sha256 instead + i dont like that when a `dev` image is built, the `dev` tag goes to top of list of tagged images
* Revert "dev action: remove `dev` tag"
This reverts commit 0179f616fa.
nevermind, that is not a thing.
* release action: add arm platform
The 'changeUserPassword' callback is updated such that error messages are passed back to the calling function in `PwChangeModal` allowing errors to show up in the same place.
Form.svelte was deleted due to not being used or needed. An associated import line in PwChangeModal.svelte has also been removed.
Additionally, setting parameter DEBUG was removed from server/config.go.
Removed a substantial block of commented-out code related to password changing in the `user.go` file, which simplifies the structure and readability of the code. Improved clarity and specificity of console debug/feedback messages throughout the frontend, ensuring easier debugging. Commit also includes minor code clean up in some files.
The commit delivers improved error handling and debugging information for password change functionality. Error messages now provide more detailed context on failures. Additionally, new password hashing has been added in the password change process. The user interface has also been updated to reflect specific error messages returned from the API.
The password change function now involves first querying user data from the database, before checking the validity of their old password. Logic has been updated on both frontend and backend code. Errors have been added for handling instances where password comparison, user retrieval or other processes fail.
A new feature has been added that allows users to change their password. This includes updates in several different files to accommodate this new functionality. Changes include adding a new API endpoint, creating a new function to handle the password change request, and removing the username field from the ChangePasswordForm interface.
Updated form validation to check for missing inputs and ensure consistency between new password and re-entered new password. Enhanced logging for better status tracking and error reporting during form validation process.
A new interface ChangePasswordForm has been created to handle password change form data.
The 'PwChangeModal.svelte' modal allows the user to input current and new passwords for a change password request.
The user profile page has been updated to include a "Change Password" button which triggers the change password modal.
Added a new store variable 'watchedListErrorOccurred' set to true if `getPublicWatchedList()` promise errors.
The aim is that the filter and sort functionality only show if the watched list loads in successfully.
the lowercase name is too annoying, must have the capital W. Hopefully the bg colour can fix issues where the icon isn't scaled up, but white was shown so it looked odd. That may mask the issue.
decided it would be harder to add multiple server support down the road than to just do it right the first time.
modal wont autosave. One endpoint to get all details needed for modal (/test).
to get safe version of config.. still manual for now until i figure out a better way (since we cant us struct tag since we do need the other properties for file)
had to rework content pages to allow for navigating to another show/movie, since sveltekit wont refresh the whole page when only changing a page parameter
and use it to store user info in a writable store (instead of using localStorage). This will let us easily add more info in the future without requiring the user to login again.
Turns out the goto in import/process will still run after the first goto we run in the layout file if theres no token, so it's possible to end up on /import if you navigate to /import/process first.
added quick fix
so we can manipulate it.
- When navigating to a search url without searching yourself, we can add the query to the search bar.
- When search page destroys (is navigated away from), we can remove the query from search bar.
Reworked Poster, instead of callbacks, handled by the page, Poster just handles the actions itself.
PosterList now supports vertical lists.
Poster can now be `small`
Just chrome on mobile has a keyboard jiggle (firefox the champ is good) after search, it seems like not so much an issue with the increased time to type.
<titledata-rh="true">Page Not Found | Watcharr Docs</title><metadata-rh="true"name="viewport"content="width=device-width,initial-scale=1"><metadata-rh="true"name="twitter:card"content="summary_large_image"><metadata-rh="true"property="og:image"content="https://watcharr.app/img/social-card.png"><metadata-rh="true"name="twitter:image"content="https://watcharr.app/img/social-card.png"><metadata-rh="true"property="og:url"content="https://watcharr.app/404.html"><metadata-rh="true"property="og:locale"content="en"><metadata-rh="true"name="docusaurus_locale"content="en"><metadata-rh="true"name="docusaurus_tag"content="default"><metadata-rh="true"name="docsearch:language"content="en"><metadata-rh="true"name="docsearch:docusaurus_tag"content="default"><metadata-rh="true"property="og:title"content="Page Not Found | Watcharr Docs"><linkdata-rh="true"rel="icon"href="/img/favicon.png"><linkdata-rh="true"rel="canonical"href="https://watcharr.app/404.html"><linkdata-rh="true"rel="alternate"href="https://watcharr.app/404.html"hreflang="en"><linkdata-rh="true"rel="alternate"href="https://watcharr.app/404.html"hreflang="x-default"><linkrel="stylesheet"href="/assets/css/styles.b440cd64.css">
<script>document.documentElement.setAttribute("data-theme","light"),document.documentElement.setAttribute("data-theme-choice","light"),function(){try{constc=newURLSearchParams(window.location.search).entries();for(var[t,e]ofc)if(t.startsWith("docusaurus-data-")){vara=t.replace("docusaurus-data-","data-");document.documentElement.setAttribute(a,e)}}catch(t){}}()</script><divid="__docusaurus"><linkrel="preload"as="image"href="/img/favicon.png"><divrole="region"aria-label="Skip to main content"><aclass="skipToContent_fXgn"href="#__docusaurus_skipToContent_fallback">Skip to main content</a></div><navaria-label="Main"class="theme-layout-navbar navbar navbar--fixed-top"><divclass="navbar__inner"><divclass="theme-layout-navbar-left navbar__items"><buttonaria-label="Toggle navigation bar"aria-expanded="false"class="navbar__toggle clean-btn"type="button"><svgwidth="30"height="30"viewBox="0 0 30 30"aria-hidden="true"><pathstroke="currentColor"stroke-linecap="round"stroke-miterlimit="10"stroke-width="2"d="M4 7h22M4 15h22M4 23h22"></path></svg></button><aclass="navbar__brand"href="/"><divclass="navbar__logo"><imgsrc="/img/favicon.png"alt="Watcharr Logo"class="themedComponent_mlkZ themedComponent--light_NVdE"><imgsrc="/img/favicon.png"alt="Watcharr Logo"class="themedComponent_mlkZ themedComponent--dark_xIcU"></div><bclass="navbar__title text--truncate">Watcharr</b></a><aclass="navbar__item navbar__link"href="/docs/introduction">Docs</a><aclass="navbar__item navbar__link"href="/docs/introduction">Next</a></div><divclass="theme-layout-navbar-right navbar__items navbar__items--right"><ahref="https://beta.watcharr.app"target="_blank"rel="noopener noreferrer"class="navbar__item navbar__link">Demo<svgwidth="13.5"height="13.5"aria-label="(opens in new tab)"class="iconExternalLink_nPIU"><usehref="#theme-svg-external-link"></use></svg></a><ahref="https://github.com/sbondCo/Watcharr"target="_blank"rel="noopener noreferrer"class="navbar__item navbar__link">GitHub<svgwidth="13.5"height="13.5"aria-label="(opens in new tab)"class="iconExternalLink_nPIU"><usehref="#theme-svg-external-link"></use></svg></a><divclass="navbarSearchContainer_Bca1"></div></div></div><divrole="presentation"class="navbar-sidebar__backdrop"></div></nav><divid="__docusaurus_skipToContent_fallback"class="theme-layout-main main-wrapper mainWrapper_z2l0"><mainclass="container margin-vert--xl"><divclass="row"><divclass="col col--6 col--offset-3"><h1class="hero__title">Page Not Found</h1><p>We could not find what you were looking for.</p><p>Please contact the owner of the site that linked you to the original URL and let them know their link is broken.</p></div></div></main></div></div>
First of all, thank you for looking into contributing! 🫡
Feel free to contribute in any way: 🐞 bug reports, 💡 ideas, 🥖 new features etc - everything is welcome!
For big PRs (lots of changes/big change in the way something works), if you'd like, it can be discussed first in an issue (dont want to waste anyones time!).
## Project Board
We have a [board to organize new features and bug fixes](https://github.com/orgs/sbondCo/projects/9/views/2) to be worked on. If you see something you'd like to work on, just ask in the issue and it can be assigned to you. Even if it isn't set for the next milestone already, it can be.
I'm your new easily self-hosted content watched list. The place you store your watched (or watching, planned, etc) **movies** and **tv shows** (and **anime**), rate them and track their status.
With [some extra configuration](https://watcharr.app/docs/server_config/game-support-igdb) I can also track your **video games**.
I am built with Go and Svelte(Kit).
Feel free to abuse this demo instance (nicely), which runs on the latest `dev` build (there may be bugs, as new features are tested on here too): [https://beta.watcharr.app/](https://beta.watcharr.app/)
[Track Progress Until Next Version](https://github.com/orgs/sbondCo/projects/9/views/3)
[Checkout our documentation](https://watcharr.app/docs/category/installation) for an up to date guide on setup! If you hate manuals, but love docker, this [docker-compose.yml](./docker-compose.yml) file is your friend.
# Getting Help
If something isn't working for you or you are stuck, [creating an issue](https://github.com/sbondCo/Watcharr/issues/new) is the best way to get help! Every type of issue is accepted, so don't be afraid to ask anything!
You can also [join our space on Matrix](https://matrix.to/#/#watcharr:matrix.org) for support.
"use strict";(globalThis.webpackChunkwatcharr_doc=globalThis.webpackChunkwatcharr_doc||[]).push([[237],{3363(e,t,i){i.d(t,{A:()=>s});i(6540);varn=i(4164),o=i(1312),a=i(1107),r=i(4848);functions({className:e}){return(0,r.jsx)("main",{className:(0,n.A)("container margin-vert--xl",e),children:(0,r.jsx)("div",{className:"row",children:(0,r.jsxs)("div",{className:"col col--6 col--offset-3",children:[(0,r.jsx)(a.A,{as:"h1",className:"hero__title",children:(0,r.jsx)(o.A,{id:"theme.NotFound.title",description:"The title of the 404 page",children:"Page Not Found"})}),(0,r.jsx)("p",{children:(0,r.jsx)(o.A,{id:"theme.NotFound.p1",description:"The first paragraph of the 404 page",children:"We could not find what you were looking for."})}),(0,r.jsx)("p",{children:(0,r.jsx)(o.A,{id:"theme.NotFound.p2",description:"The 2nd paragraph of the 404 page",children:"Please contact the owner of the site that linked you to the original URL and let them know their link is broken."})})]})})})}},2237(e,t,i){i.r(t),i.d(t,{default:()=>h});i(6540);varn=i(1312),o=i(5500),a=i(1656),r=i(3363),s=i(4848);functionh(){conste=(0,n.T)({id:"theme.NotFound.title",message:"Page Not Found"});return(0,s.jsxs)(s.Fragment,{children:[(0,s.jsx)(o.be,{title:e}),(0,s.jsx)(a.A,{children:(0,s.jsx)(r.A,{})})]})}}}]);
"use strict";(globalThis.webpackChunkwatcharr_doc=globalThis.webpackChunkwatcharr_doc||[]).push([[990],{6948(e,r,t){t.r(r),t.d(r,{assets:()=>c,contentTitle:()=>s,default:()=>h,frontMatter:()=>a,metadata:()=>o,toc:()=>d});consto=JSON.parse('{"id":"importing/watcharr","title":"Watcharr","description":"You may consider a backup of your server before starting any import. They are not easily reversible, though we do our best to ensure they are accurate and bug free!","source":"@site/docs/importing/watcharr.md","sourceDirName":"importing","slug":"/importing/watcharr","permalink":"/docs/importing/watcharr","draft":false,"unlisted":false,"editUrl":"https://github.com/sbondCo/Watcharr/tree/dev/doc/docs/importing/watcharr.md","tags":[],"version":"current","sidebarPosition":0,"frontMatter":{"sidebar_position":0},"sidebar":"tutorialSidebar","previous":{"title":"Importing","permalink":"/docs/category/importing"},"next":{"title":"Text File (.txt list)","permalink":"/docs/importing/text-file"}}');varn=t(4848),i=t(8453);consta={sidebar_position:0},s="Watcharr",c={},d=[];functionl(e){constr={a:"a",admonition:"admonition",h1:"h1",header:"header",li:"li",ol:"ol",p:"p",...(0,i.R)(),...e.components};return(0,n.jsxs)(n.Fragment,{children:[(0,n.jsx)(r.header,{children:(0,n.jsx)(r.h1,{id:"watcharr",children:"Watcharr"})}),"\n",(0,n.jsx)(r.admonition,{title:"Backup?",type:"info",children:(0,n.jsx)(r.p,{children:"You may consider a backup of your server before starting any import. They are not easily reversible, though we do our best to ensure they are accurate and bug free!"})}),"\n",(0,n.jsx)(r.admonition,{title:"May not be what you want",type:"warning",children:(0,n.jsxs)(r.p,{children:["Watcharr import/export is a feature intended for end users. If you are the server admin, it is recommended that you copy your server files directly to any new server you are creating (it'll be much faster and easier). ",(0,n.jsx)(r.a,{href:"/docs/server_config/backup",children:"See backup guide"}),"."]})}),"\n",(0,n.jsxs)(r.ol,{children:["\n",(0,n.jsx)(r.li,{children:"Provide the Watcharr export file (that you generated from your profile page)."}),"\n",(0,n.jsx)(r.li,{children:"Review the import table, if everything looks good, start the import."}),"\n"]})]})}functionh(e={}){const{wrapper:r}={...(0,i.R)(),...e.components};returnr?(0,n.jsx)(r,{...e,children:(0,n.jsx)(l,{...e})}):l(e)}},8453(e,r,t){t.d(r,{R:()=>a,x:()=>s});varo=t(6540);constn={},i=o.createContext(n);functiona(e){constr=o.useContext(i);returno.useMemo(function(){return"function"==typeofe?e(r):{...r,...e}},[r,e])}functions(e){letr;returnr=e.disableParentContext?"function"==typeofe.components?e.components(n):e.components||n:a(e.components),o.createElement(i.Provider,{value:r},e.children)}}}]);
"use strict";(globalThis.webpackChunkwatcharr_doc=globalThis.webpackChunkwatcharr_doc||[]).push([[449],{9095(e,t,n){n.r(t),n.d(t,{assets:()=>c,contentTitle:()=>a,default:()=>l,frontMatter:()=>r,metadata:()=>s,toc:()=>d});consts=JSON.parse('{"id":"usage/adding-to-watchlist","title":"Adding To Your Watchlist","description":"Adding movies or shows to your watchlist is the core feature of Watcharr.","source":"@site/docs/usage/adding-to-watchlist.md","sourceDirName":"usage","slug":"/usage/adding-to-watchlist","permalink":"/docs/usage/adding-to-watchlist","draft":false,"unlisted":false,"editUrl":"https://github.com/sbondCo/Watcharr/tree/dev/doc/docs/usage/adding-to-watchlist.md","tags":[],"version":"current","sidebarPosition":1,"frontMatter":{"sidebar_position":1},"sidebar":"tutorialSidebar","previous":{"title":"Usage","permalink":"/docs/category/usage"}}');varo=n(4848),i=n(8453);constr={sidebar_position:1},a="Adding To Your Watchlist",c={},d=[];functionh(e){constt={code:"code",em:"em",h1:"h1",header:"header",img:"img",li:"li",ol:"ol",p:"p",...(0,i.R)(),...e.components};return(0,o.jsxs)(o.Fragment,{children:[(0,o.jsx)(t.header,{children:(0,o.jsx)(t.h1,{id:"adding-to-your-watchlist",children:"Adding To Your Watchlist"})}),"\n",(0,o.jsx)(t.p,{children:"Adding movies or shows to your watchlist is the core feature of Watcharr."}),"\n",(0,o.jsx)(t.p,{children:"The homepage is where your list will appear once you have added some."}),"\n",(0,o.jsx)(t.p,{children:"To get started, you can follow along with these steps to add your first movie/show:"}),"\n",(0,o.jsxs)(t.ol,{children:["\n",(0,o.jsxs)(t.li,{children:["\n",(0,o.jsx)(t.p,{children:"Search for the content:"}),"\n",(0,o.jsx)(t.p,{children:(0,o.jsx)(t.img,{alt:"Searching For Content",src:n(8406).A+"",width:"745",height:"440"})}),"\n"]}),"\n",(0,o.jsxs)(t.li,{children:["\n",(0,o.jsx)(t.p,{children:"Hover or click on the content you want to add:"}),"\n",(0,o.jsx)(t.p,{children:(0,o.jsx)(t.img,{alt:"Hovering over poster",src:n(6320).A+"",width:"745",height:"440"})}),"\n"]}),"\n",(0,o.jsxs)(t.li,{children:["\n",(0,o.jsx)(t.p,{children:"Clicking the + (Plus) icon will let you give the content a status."}),"\n",(0,o.jsxs)(t.p,{children:["Currently supported statuses include: ",(0,o.jsx)(t.code,{children:"Finished"}),", ",(0,o.jsx)(t.code,{children:"Watching"}),", ",(0,o.jsx)(t.code,{children:"Held"}),", ",(0,o.jsx)(t.code,{children:"Planned"}),", ",(0,o.jsx)(t.code,{children:"Dropped"}),"."]}),"\n",(0,o.jsx)(t.p,{children:(0,o.jsx)(t.img,{alt:"Giving content a status",src:n(2385).A+"",width:"745",height:"440"})}),"\n"]}),"\n",(0,o.jsxs)(t.li,{children:["\n",(0,o.jsx)(t.p,{children:"Rate the content."}),"\n",(0,o.jsx)(t.p,{children:(0,o.jsx)(t.img,{alt:"Giving content a rating",src:n(1985).A+"",width:"745",height:"440"})}),"\n"]}),"\n"]}),"\n",(0,o.jsxs)(t.p,{children:["If you prefer, you can also do this by clicking/tapping on the active poster again.\nThis will take you to the contents full page. Here you can see all the options, including\nadding ",(0,o.jsx)(t.code,{children:"Thoughts"})," for the content."]}),"\n",(0,o.jsx)(t.p,{children:(0,o.jsx)(t.img,{alt:"Content full page",src:n(8234).A+"",width:"745",height:"837"})}),"\n",(0,o.jsxs)(t.p,{children:[(0,o.jsx)(t.code,{children:"Thoughts"})," can be anything you would like to write down or remember about the specific movie/show.\nFor example, sometimes I like to write something specific that I ",(0,o.jsx)(t.em,{children:"really"})," liked about the content,\nor for some shows, I write down my favourite seasons and how many times I have watched them."]})]})}functionl(e={}){const{wrapper:t}={...(0,i.R)(),...e.components};returnt?(0,o.jsx)(t,{...e,children:(0,o.jsx)(h,{...e})}):h(e)}},8234(e,t,n){n.d(t,{A:()=>s});consts=n.p+"assets/images/content-full-page-4cdac3f6a414c03b6231b32db57cd7ff.png"},1985(e,t,n){n.d(t,{A:()=>s});consts=n.p+"assets/images/search-for-content-hover-poster-rate-23ebec4c88db3592961ba6d72a75183e.png"},2385(e,t,n){n.d(t,{A:()=>s});consts=n.p+"assets/images/search-for-content-hover-poster-status-19fe5d733c26eb921d1ae59e37717d19.png"},6320(e,t,n){n.d(t,{A:()=>s});consts=n.p+"assets/images/search-for-content-hover-poster-6574ac86e280bfa112b04635b9689e9a.png"},8406(e,t,n){n.d(t,{A:()=>s});consts=n.p+"assets/images/search-for-content-c81935a18e93b262ca2adb89783fa9aa.png"},8453(e,t,n){n.d(t,{R:()=>r,x:()=>a});vars=n(6540);consto={},i=s.createContext(o);functionr(e){constt=s.useContext(i);returns.useMemo(function(){return"function"==typeofe?e(t):{...t,...e}},[t,e])}functiona(e){lett;returnt=e.disableParentContext?"function"==typeofe.components?e.components(o):e.components||o:r(e.components),s.createElement(i.Provider,{value:t},e.children)}}}]);
"use strict";(globalThis.webpackChunkwatcharr_doc=globalThis.webpackChunkwatcharr_doc||[]).push([[671],{2040(e,r,t){t.r(r),t.d(r,{assets:()=>c,contentTitle:()=>o,default:()=>u,frontMatter:()=>a,metadata:()=>n,toc:()=>d});constn=JSON.parse('{"id":"server_config/backup","title":"Backing Up","description":"Backing up your server.","source":"@site/docs/server_config/backup.md","sourceDirName":"server_config","slug":"/server_config/backup","permalink":"/docs/server_config/backup","draft":false,"unlisted":false,"editUrl":"https://github.com/sbondCo/Watcharr/tree/dev/doc/docs/server_config/backup.md","tags":[],"version":"current","sidebarPosition":100,"frontMatter":{"sidebar_position":100,"description":"Backing up your server."},"sidebar":"tutorialSidebar","previous":{"title":"Environment Variables","permalink":"/docs/server_config/environment-variables"},"next":{"title":"Importing","permalink":"/docs/category/importing"}}');vari=t(4848),s=t(8453);consta={sidebar_position:100,description:"Backing up your server."},o="Backing Up",c={},d=[{value:"Simple Steps",id:"simple-steps",level:2},{value:"Advanced Steps",id:"advanced-steps",level:2}];functionl(e){constr={admonition:"admonition",code:"code",h1:"h1",h2:"h2",header:"header",li:"li",ol:"ol",p:"p",ul:"ul",...(0,s.R)(),...e.components};return(0,i.jsxs)(i.Fragment,{children:[(0,i.jsx)(r.header,{children:(0,i.jsx)(r.h1,{id:"backing-up",children:"Backing Up"})}),"\n",(0,i.jsx)(r.p,{children:"Watcharr cannot handle backing up for you, but its simple structure should make it easy to slide it into your existing backup routine."}),"\n",(0,i.jsx)(r.p,{children:"Once you have created your first backup, it's recommended that you try restoring from that backup to make sure everything is correct and will work in case you need to restore from it in the future."}),"\n",(0,i.jsx)(r.admonition,{title:"Shutdown your server!",type:"danger",children:(0,i.jsx)(r.p,{children:"Always shutdown Watcharr before backing up its data, otherwise you run the risk of corrupting files (mainly your database)."})}),"\n",(0,i.jsx)(r.h2,{id:"simple-steps",children:"Simple Steps"}),"\n",(0,i.jsx)(r.admonition,{title:"Recommended",type:"success",children:(0,i.jsx)(r.p,{children:"This is the recommended way to backup."})}),"\n",(0,i.jsxs)(r.p,{children:["Here are the steps that are run daily for the ",(0,i.jsx)(r.code,{children:"beta.watcharr.app"})," instance."]}),"\n",(0,i.jsxs)(r.ol,{children:["\n",(0,i.jsx)(r.li,{children:"Shutdown Watcharr."}),"\n",(0,i.jsxs)(r.li,{children:["Copy and backup the entire ",(0,i.jsx)(r.code,{children:"data"})," folder (default location is ",(0,i.jsx)(r.code,{children:"./data"}),", backup whichever folder your server is configured to store its data in)."]}),"\n",(0,i.jsx)(r.li,{children:"Start Watcharr."}),"\n"]}),"\n",(0,i.jsx)(r.p,{children:"I call these the simple steps because they simply backup your entire server, if you ever need to restore your server, it will start up from its exact state at backup."}),"\n",(0,i.jsx)(r.h2,{id:"advanced-steps",children:"Advanced Steps"}),"\n",(0,i.jsx)(r.admonition,{title:"Discouraged",type:"danger",children:(0,i.jsx)(r.p,{children:"Backing up this way is discouraged because new important files could be added later and missed."})}),"\n",(0,i.jsx)(r.p,{children:'If you don\'t care about the warning not to backup this way, here are the "important" files that you can single out for backup:'}),"\n",(0,i.jsxs)(r.ul,{children:["\n",(0,i.jsxs)(r.li,{children:[(0,i.jsx)(r.code,{children:"watcharr.db"})," & ",(0,i.jsx)(r.code,{children:"watcharr.db-wal"})," Your database, holds all users, their watchlists, etc."]}),"\n",(0,i.jsxs)(r.li,{children:[(0,i.jsx)(r.code,{children:"watcharr.json"})," Server config."]}),"\n",(0,i.jsxs)(r.li,{children:[(0,i.jsx)(r.code,{children:"img/up"})," Profile picture uploads."]}),"\n",(0,i.jsxs)(r.li,{children:[(0,i.jsx)(r.code,{children:"img/games"})," Game posters (not exactly important, but scenarios in which this folder is not backed up have not been tested, only relevant for servers with game support enabled)."]}),"\n"]})]})}functionu(e={}){const{wrapper:r}={...(0,s.R)(),...e.components};returnr?(0,i.jsx)(r,{...e,children:(0,i.jsx)(l,{...e})}):l(e)}},8453(e,r,t){t.d(r,{R:()=>a,x:()=>o});varn=t(6540);consti={},s=n.createContext(i);functiona(e){constr=n.useContext(s);returnn.useMemo(function(){return"function"==typeofe?e(r):{...r,...e}},[r,e])}functiono(e){letr;returnr=e.disableParentContext?"function"==typeofe.components?e.components(i):e.components||i:a(e.components),n.createElement(s.Provider,{value:r},e.children)}}}]);
"use strict";(globalThis.webpackChunkwatcharr_doc=globalThis.webpackChunkwatcharr_doc||[]).push([[352],{5421(e){e.exports=JSON.parse('{"categoryGeneratedIndex":{"title":"Usage","description":"Hopefully Watcharr is easy enough to get started with and use, but incase you are stuck, one of these usage guides may help.","slug":"/category/usage","permalink":"/docs/category/usage","sidebar":"tutorialSidebar","navigation":{"previous":{"title":"Trakt","permalink":"/docs/importing/trakt"},"next":{"title":"Adding To Your Watchlist","permalink":"/docs/usage/adding-to-watchlist"}}}}')}}]);
"use strict";(globalThis.webpackChunkwatcharr_doc=globalThis.webpackChunkwatcharr_doc||[]).push([[899],{1920(t,e,n){n.r(e),n.d(e,{assets:()=>c,contentTitle:()=>s,default:()=>l,frontMatter:()=>a,metadata:()=>o,toc:()=>d});consto=JSON.parse('{"id":"introduction","title":"Introduction","description":"Watcharr is for the peeps who like to keep a list of all the content they have ever watched.","source":"@site/docs/introduction.md","sourceDirName":".","slug":"/introduction","permalink":"/docs/introduction","draft":false,"unlisted":false,"editUrl":"https://github.com/sbondCo/Watcharr/tree/dev/doc/docs/introduction.md","tags":[],"version":"current","sidebarPosition":1,"frontMatter":{"sidebar_position":1},"sidebar":"tutorialSidebar","next":{"title":"Installation","permalink":"/docs/category/installation"}}');varr=n(4848),i=n(8453);consta={sidebar_position:1},s="Introduction",c={},d=[];functionh(t){conste={a:"a",h1:"h1",header:"header",p:"p",...(0,i.R)(),...t.components};return(0,r.jsxs)(r.Fragment,{children:[(0,r.jsx)(e.header,{children:(0,r.jsx)(e.h1,{id:"introduction",children:"Introduction"})}),"\n",(0,r.jsx)(e.p,{children:"Watcharr is for the peeps who like to keep a list of all the content they have ever watched."}),"\n",(0,r.jsxs)(e.p,{children:["If you would like more insight, the ",(0,r.jsx)(e.a,{href:"/docs/usage/adding-to-watchlist",children:"adding to your watchlist guide"}),"\nis a great example of how Watcharr is used."]})]})}functionl(t={}){const{wrapper:e}={...(0,i.R)(),...t.components};returne?(0,r.jsx)(e,{...t,children:(0,r.jsx)(h,{...t})}):h(t)}},8453(t,e,n){n.d(e,{R:()=>a,x:()=>s});varo=n(6540);constr={},i=o.createContext(r);functiona(t){conste=o.useContext(i);returno.useMemo(function(){return"function"==typeoft?t(e):{...e,...t}},[e,t])}functions(t){lete;returne=t.disableParentContext?"function"==typeoft.components?t.components(r):t.components||r:a(t.components),o.createElement(i.Provider,{value:e},t.children)}}}]);
"use strict";(globalThis.webpackChunkwatcharr_doc=globalThis.webpackChunkwatcharr_doc||[]).push([[887],{3419(e,n,t){t.r(n),t.d(n,{assets:()=>c,contentTitle:()=>i,default:()=>h,frontMatter:()=>r,metadata:()=>o,toc:()=>l});consto=JSON.parse('{"id":"installation/docker-compose","title":"Docker Compose","description":"Install and setup with Docker Compose.","source":"@site/docs/installation/docker-compose.md","sourceDirName":"installation","slug":"/installation/docker-compose","permalink":"/docs/installation/docker-compose","draft":false,"unlisted":false,"editUrl":"https://github.com/sbondCo/Watcharr/tree/dev/doc/docs/installation/docker-compose.md","tags":[],"version":"current","sidebarPosition":1,"frontMatter":{"sidebar_position":1,"description":"Install and setup with Docker Compose."},"sidebar":"tutorialSidebar","previous":{"title":"Installation","permalink":"/docs/category/installation"},"next":{"title":"From Source","permalink":"/docs/installation/from-source"}}');vars=t(4848),a=t(8453);constr={sidebar_position:1,description:"Install and setup with Docker Compose."},i="Docker Compose",c={},l=[{value:"Installing",id:"installing",level:2},{value:"Updating",id:"updating",level:2}];functiond(e){constn={a:"a",admonition:"admonition",code:"code",h1:"h1",h2:"h2",header:"header",li:"li",ol:"ol",p:"p",pre:"pre",strong:"strong",...(0,a.R)(),...e.components};return(0,s.jsxs)(s.Fragment,{children:[(0,s.jsx)(n.header,{children:(0,s.jsx)(n.h1,{id:"docker-compose",children:"Docker Compose"})}),"\n",(0,s.jsx)(n.h2,{id:"installing",children:"Installing"}),"\n",(0,s.jsx)(n.p,{children:"Installing Watcharr with a docker compose file is easy. You can copy the example below to get started:"}),"\n",(0,s.jsx)(n.pre,{children:(0,s.jsx)(n.code,{className:"language-yaml",metastring:'title="docker-compose.yml"',children:"services:\n watcharr:\n # The :latest tag is used for simplicity, it is recommended\n # to use an actual version, then when updating check the releases for changelogs.\n image: ghcr.io/sbondco/watcharr:latest\n container_name: watcharr\n ports:\n - 3080:3080\n volumes:\n # Contains all of watcharr data (database & cache)\n - ./data:/data\n restart: unless-stopped\n"})}),"\n",(0,s.jsx)(n.admonition,{title:"first account",type:"danger",children:(0,s.jsxs)(n.p,{children:["When ",(0,s.jsx)(n.strong,{children:"first"})," running Watcharr, make sure only you have access. The first user created will become admin."]})}),"\n",(0,s.jsxs)(n.p,{children:["You can now start ",(0,s.jsx)(n.code,{children:"Watcharr"})," like so:"]}),"\n",(0,s.jsx)(n.pre,{children:(0,s.jsx)(n.code,{className:"language-bash",children:"docker compose up -d\n"})}),"\n",(0,s.jsxs)(n.p,{children:["If you didn't change the ports in the example, the server will be available at ",(0,s.jsx)(n.a,{href:"http://localhost:3080/",children:"http://localhost:3080/"}),"."]}),"\n",(0,s.jsx)(n.h2,{id:"updating",children:"Updating"}),"\n",(0,s.jsxs)(n.admonition,{title:"Take care",type:"danger",children:[(0,s.jsx)(n.p,{children:"We try taking care as to not release breaking changes, however it is still recommended that\nyou lookover changelogs before updating!"}),(0,s.jsxs)(n.p,{children:["Breaking changes are marked at the top of releases: ",(0,s.jsx)(n.a,{href:"https://github.com/sbondCo/Watcharr/releases",children:"https://github.com/sbondCo/Watcharr/releases"})]})]}),"\n",(0,s.jsx)(n.p,{children:"Updating your server can be done in two steps:"}),"\n",(0,s.jsxs)(n.ol,{children:["\n",(0,s.jsxs)(n.li,{children:["\n",(0,s.jsxs)(n.p,{children:["Update the ",(0,s.jsx)(n.code,{children:"image"})," version in your ",(0,s.jsx)(n.code,{children:"docker-compose.yml"})," file.\nSkip this step if you are using the ",(0,s.jsx)(n.code,{children:"latest"})," tag."]}),"\n",(0,s.jsx)(n.pre,{children:(0,s.jsx)(n.code,{className:"language-yaml",children:"# eg. update v1.19.0 to v1.20.0 (or whatever version you are updating to)\nimage: ghcr.io/sbondco/watcharr:v1.19.0\n"})}),"\n"]}),"\n",(0,s.jsxs)(n.li,{children:["\n",(0,s.jsx)(n.p,{children:"Pull the new changes and re-create your container:"}),"\n",(0,s.jsx)(n.pre,{children:(0,s.jsx)(n.code,{className:"language-bash",children:"docker compose pull && docker compose down && docker compose up -d\n"})}),"\n"]}),"\n"]}),"\n",(0,s.jsx)(n.p,{children:"And that is it!"})]})}functionh(e={}){const{wrapper:n}={...(0,a.R)(),...e.components};returnn?(0,s.jsx)(n,{...e,children:(0,s.jsx)(d,{...e})}):d(e)}},8453(e,n,t){t.d(n,{R:()=>r,x:()=>i});varo=t(6540);consts={},a=o.createContext(s);functionr(e){constn=o.useContext(a);returno.useMemo(function(){return"function"==typeofe?e(n):{...n,...e}},[n,e])}functioni(e){letn;returnn=e.disableParentContext?"function"==typeofe.components?e.components(s):e.components||s:r(e.components),o.createElement(a.Provider,{value:n},e.children)}}}]);
"use strict";(globalThis.webpackChunkwatcharr_doc=globalThis.webpackChunkwatcharr_doc||[]).push([[287],{934(e,t,n){n.r(t),n.d(t,{assets:()=>c,contentTitle:()=>a,default:()=>h,frontMatter:()=>s,metadata:()=>i,toc:()=>l});consti=JSON.parse('{"id":"importing/trakt","title":"Trakt","description":"You may consider a backup of your server before starting any import. They are not easily reversible, though we do our best to ensure they are accurate and bug free!","source":"@site/docs/importing/trakt.md","sourceDirName":"importing","slug":"/importing/trakt","permalink":"/docs/importing/trakt","draft":false,"unlisted":false,"editUrl":"https://github.com/sbondCo/Watcharr/tree/dev/doc/docs/importing/trakt.md","tags":[],"version":"current","sidebarPosition":3,"frontMatter":{"sidebar_position":3},"sidebar":"tutorialSidebar","previous":{"title":"MyAnimeList","permalink":"/docs/importing/myanimelist"},"next":{"title":"Usage","permalink":"/docs/category/usage"}}');varr=n(4848),o=n(8453);consts={sidebar_position:3},a="Trakt",c={},l=[{value:"(Optional) API Key",id:"optional-api-key",level:3},{value:"Getting an API Key",id:"getting-an-api-key",level:4}];functiond(e){constt={a:"a",admonition:"admonition",code:"code",em:"em",h1:"h1",h3:"h3",h4:"h4",header:"header",li:"li",ol:"ol",p:"p",strong:"strong",...(0,o.R)(),...e.components};return(0,r.jsxs)(r.Fragment,{children:[(0,r.jsx)(t.header,{children:(0,r.jsx)(t.h1,{id:"trakt",children:"Trakt"})}),"\n",(0,r.jsx)(t.admonition,{title:"Backup?",type:"info",children:(0,r.jsx)(t.p,{children:"You may consider a backup of your server before starting any import. They are not easily reversible, though we do our best to ensure they are accurate and bug free!"})}),"\n",(0,r.jsxs)(t.p,{children:[(0,r.jsx)(t.strong,{children:"Note:"})," Your Trakt profile must be public ",(0,r.jsx)(t.em,{children:"during"})," this process. You are free to private it again once it completes."]}),"\n",(0,r.jsxs)(t.ol,{children:["\n",(0,r.jsx)(t.li,{children:"Provide your Trakt username in the text box."}),"\n",(0,r.jsxs)(t.li,{children:["(Optional) ",(0,r.jsx)(t.a,{href:"#optional-api-key",children:"Provide your own api key"}),"."]}),"\n",(0,r.jsxs)(t.li,{children:["Press ",(0,r.jsx)(t.code,{children:"Start Import"}),"."]}),"\n"]}),"\n",(0,r.jsx)(t.p,{children:"This will be a long process, possibly a couple hours depending on how large of a Trakt history you have. If you think it has frozen or isn't working, try checking your server logs to see if it is doing anything."}),"\n",(0,r.jsx)(t.h3,{id:"optional-api-key",children:"(Optional) API Key"}),"\n",(0,r.jsxs)(t.p,{children:["This step is optional because Watcharr comes built in with its own API Key that it can use for your import, however, if you encounter any issues where imports cannot start or keep failing and you see any ",(0,r.jsx)(t.code,{children:"403"})," errors in your server logs, providing your own key may fix the problem."]}),"\n",(0,r.jsx)(t.h4,{id:"getting-an-api-key",children:"Getting an API Key"}),"\n",(0,r.jsxs)(t.ol,{children:["\n",(0,r.jsxs)(t.li,{children:[(0,r.jsx)(t.a,{href:"https://trakt.tv/oauth/applications/new",children:"Visit this link to create a new Trakt API App"}),"."]}),"\n",(0,r.jsxs)(t.li,{children:["Fill out all required fields (",(0,r.jsx)(t.code,{children:"Name"})," and ",(0,r.jsx)(t.code,{children:"Redirect uri"}),") with any random data.","\n",(0,r.jsxs)(t.ol,{children:["\n",(0,r.jsxs)(t.li,{children:["You can set the ",(0,r.jsx)(t.code,{children:"Redirect uri"})," to any value the input accepts since we don't use it (eg: ",(0,r.jsx)(t.code,{children:"http://localhost"}),")"]}),"\n"]}),"\n"]}),"\n",(0,r.jsxs)(t.li,{children:["Click ",(0,r.jsx)(t.code,{children:"Save App"}),"."]}),"\n",(0,r.jsxs)(t.li,{children:["You should now be redirected to your new app. Copy the ",(0,r.jsx)(t.code,{children:"Client ID"})," into the ",(0,r.jsx)(t.code,{children:"API Key"})," textbox in Watcharr."]}),"\n"]})]})}functionh(e={}){const{wrapper:t}={...(0,o.R)(),...e.components};returnt?(0,r.jsx)(t,{...e,children:(0,r.jsx)(d,{...e})}):d(e)}},8453(e,t,n){n.d(t,{R:()=>s,x:()=>a});vari=n(6540);constr={},o=i.createContext(r);functions(e){constt=i.useContext(o);returni.useMemo(function(){return"function"==typeofe?e(t):{...t,...e}},[t,e])}functiona(e){lett;returnt=e.disableParentContext?"function"==typeofe.components?e.components(r):e.components||r:s(e.components),i.createElement(o.Provider,{value:t},e.children)}}}]);
"use strict";(globalThis.webpackChunkwatcharr_doc=globalThis.webpackChunkwatcharr_doc||[]).push([[157],{2640(e,n,r){r.r(n),r.d(n,{assets:()=>c,contentTitle:()=>s,default:()=>u,frontMatter:()=>o,metadata:()=>t,toc:()=>l});constt=JSON.parse('{"id":"server_config/environment-variables","title":"Environment Variables","description":"All environment variables you can use to start your server in a specific way.","source":"@site/docs/server_config/environment-variables.md","sourceDirName":"server_config","slug":"/server_config/environment-variables","permalink":"/docs/server_config/environment-variables","draft":false,"unlisted":false,"editUrl":"https://github.com/sbondCo/Watcharr/tree/dev/doc/docs/server_config/environment-variables.md","tags":[],"version":"current","sidebarPosition":11,"frontMatter":{"sidebar_position":11,"description":"All environment variables you can use to start your server in a specific way."},"sidebar":"tutorialSidebar","previous":{"title":"Restoring Admin Priviliges","permalink":"/docs/server_config/restoring-admin"},"next":{"title":"Backing Up","permalink":"/docs/server_config/backup"}}');vari=r(4848),a=r(8453);consto={sidebar_position:11,description:"All environment variables you can use to start your server in a specific way."},s="Environment Variables",c={},l=[{value:"<code>WATCHARR_DATA</code>",id:"watcharr_data",level:2}];functiond(e){constn={code:"code",h1:"h1",h2:"h2",header:"header",p:"p",...(0,a.R)(),...e.components};return(0,i.jsxs)(i.Fragment,{children:[(0,i.jsx)(n.header,{children:(0,i.jsx)(n.h1,{id:"environment-variables",children:"Environment Variables"})}),"\n",(0,i.jsx)(n.p,{children:"Currently there is only one, and maybe it will stay that way forever (because the admin interface can handle most settings). A very lonely page right now ;(."}),"\n",(0,i.jsx)(n.h2,{id:"watcharr_data",children:(0,i.jsx)(n.code,{children:"WATCHARR_DATA"})}),"\n",(0,i.jsx)(n.p,{children:"Make Watcharr use a custom directory for all of its data."}),"\n",(0,i.jsxs)(n.p,{children:["Defaults to ",(0,i.jsx)(n.code,{children:"./data"}),"."]})]})}functionu(e={}){const{wrapper:n}={...(0,a.R)(),...e.components};returnn?(0,i.jsx)(n,{...e,children:(0,i.jsx)(d,{...e})}):d(e)}},8453(e,n,r){r.d(n,{R:()=>o,x:()=>s});vart=r(6540);consti={},a=t.createContext(i);functiono(e){constn=t.useContext(a);returnt.useMemo(function(){return"function"==typeofe?e(n):{...n,...e}},[n,e])}functions(e){letn;returnn=e.disableParentContext?"function"==typeofe.components?e.components(i):e.components||i:o(e.components),t.createElement(a.Provider,{value:n},e.children)}}}]);
"use strict";(globalThis.webpackChunkwatcharr_doc=globalThis.webpackChunkwatcharr_doc||[]).push([[361],{1860(e,t,r){r.r(t),r.d(t,{assets:()=>l,contentTitle:()=>s,default:()=>h,frontMatter:()=>a,metadata:()=>i,toc:()=>c});consti=JSON.parse('{"id":"importing/text-file","title":"Text File (.txt list)","description":"You may consider a backup of your server before starting any import. They are not easily reversible, though we do our best to ensure they are accurate and bug free!","source":"@site/docs/importing/text-file.md","sourceDirName":"importing","slug":"/importing/text-file","permalink":"/docs/importing/text-file","draft":false,"unlisted":false,"editUrl":"https://github.com/sbondCo/Watcharr/tree/dev/doc/docs/importing/text-file.md","tags":[],"version":"current","sidebarPosition":1,"frontMatter":{"sidebar_position":1},"sidebar":"tutorialSidebar","previous":{"title":"Watcharr","permalink":"/docs/importing/watcharr"},"next":{"title":"MyAnimeList","permalink":"/docs/importing/myanimelist"}}');varn=r(4848),o=r(8453);consta={sidebar_position:1},s="Text File (.txt list)",l={},c=[{value:"Format",id:"format",level:2},{value:"An example",id:"an-example",level:2}];functiond(e){constt={admonition:"admonition",code:"code",h1:"h1",h2:"h2",header:"header",li:"li",p:"p",pre:"pre",ul:"ul",...(0,o.R)(),...e.components};return(0,n.jsxs)(n.Fragment,{children:[(0,n.jsx)(t.header,{children:(0,n.jsx)(t.h1,{id:"text-file-txt-list",children:"Text File (.txt list)"})}),"\n",(0,n.jsx)(t.admonition,{title:"Backup?",type:"info",children:(0,n.jsx)(t.p,{children:"You may consider a backup of your server before starting any import. They are not easily reversible, though we do our best to ensure they are accurate and bug free!"})}),"\n",(0,n.jsx)(t.p,{children:"The text file (.txt) import is of an arbitrary format (the one I used for years before creating Watcharr)."}),"\n",(0,n.jsx)(t.p,{children:"Hopefully it is useful for others with similar files or in scenarios where its the easiest to generate for an import (though if possible, when generating a backup from another service data manually, matching a Watcharr export would enable keeping more data)."}),"\n",(0,n.jsx)(t.h2,{id:"format",children:"Format"}),"\n",(0,n.jsx)(t.p,{children:"Each line is a new entry. The name of the content (show/movie) must be provided. Doesn't support specifying if name is for a show or movie, the importer will only automatically match on full search matches, if there are multiple results, you will be asked to pick the correct one."}),"\n",(0,n.jsx)(t.p,{children:"Optionally provide:"}),"\n",(0,n.jsxs)(t.ul,{children:["\n",(0,n.jsxs)(t.li,{children:["The year in brackets (eg: ",(0,n.jsx)(t.code,{children:"(1983)"}),")"]}),"\n",(0,n.jsxs)(t.li,{children:["A rating (out of 10) in square brackets (eg: ",(0,n.jsx)(t.code,{children:"[4]"})," or ",(0,n.jsx)(t.code,{children:"[6.9]"}),")"]}),"\n"]}),"\n",(0,n.jsx)(t.pre,{children:(0,n.jsx)(t.code,{children:"<name> [(<year>)]\n"})}),"\n",(0,n.jsx)(t.h2,{id:"an-example",children:"An example"}),"\n",(0,n.jsx)(t.pre,{children:(0,n.jsx)(t.code,{children:"The Terminator (1984)\nBreaking Bad\nA Fistful of Dollars\nReacher (2022)\n"})})]})}functionh(e={}){const{wrapper:t}={...(0,o.R)(),...e.components};returnt?(0,n.jsx)(t,{...e,children:(0,n.jsx)(d,{...e})}):d(e)}},8453(e,t,r){r.d(t,{R:()=>a,x:()=>s});vari=r(6540);constn={},o=i.createContext(n);functiona(e){constt=i.useContext(o);returni.useMemo(function(){return"function"==typeofe?e(t):{...t,...e}},[t,e])}functions(e){lett;returnt=e.disableParentContext?"function"==typeofe.components?e.components(n):e.components||n:a(e.components),i.createElement(o.Provider,{value:t},e.children)}}}]);
"use strict";(globalThis.webpackChunkwatcharr_doc=globalThis.webpackChunkwatcharr_doc||[]).push([[299],{1933(e){e.exports=JSON.parse('{"categoryGeneratedIndex":{"title":"Server Configuration","description":"Learn how to configure your server.","slug":"/category/server-configuration","permalink":"/docs/category/server-configuration","sidebar":"tutorialSidebar","navigation":{"previous":{"title":"For Development","permalink":"/docs/installation/for-development"},"next":{"title":"Games Support (via IGDB/Twitch)","permalink":"/docs/server_config/game-support-igdb"}}}}')}}]);
"use strict";(globalThis.webpackChunkwatcharr_doc=globalThis.webpackChunkwatcharr_doc||[]).push([[527],{7877(r){r.exports=JSON.parse('{"categoryGeneratedIndex":{"title":"Importing","description":"Guides for importing your data from other services.","slug":"/category/importing","permalink":"/docs/category/importing","sidebar":"tutorialSidebar","navigation":{"previous":{"title":"Backing Up","permalink":"/docs/server_config/backup"},"next":{"title":"Watcharr","permalink":"/docs/importing/watcharr"}}}}')}}]);
"use strict";(globalThis.webpackChunkwatcharr_doc=globalThis.webpackChunkwatcharr_doc||[]).push([[545],{3608(o){o.exports=JSON.parse('{"categoryGeneratedIndex":{"title":"Installation","description":"Choose how you would like to install Watcharr.","slug":"/category/installation","permalink":"/docs/category/installation","sidebar":"tutorialSidebar","navigation":{"previous":{"title":"Introduction","permalink":"/docs/introduction"},"next":{"title":"Docker Compose","permalink":"/docs/installation/docker-compose"}}}}')}}]);
Game support in Watcharr, currently, must be enabled by you.
This involves setting up a Twitch developer account (phone number needed for 2FA which is required) and entering application credentials into Watcharr, that can then be used for looking up game info via IGDB.
P.S. These steps are stolen from [igdb api docs](https://api-docs.igdb.com/#account-creation), I've tried to make it easier to follow with screenshots.
## Steps
### Setup On Twitch
1. Sign up for a [Twitch](https://dev.twitch.tv/login) account.
Click login with twitch, then create an account in the Sign Up tab.
2. Enable two factor authentication in your [account Security settings](https://www.twitch.tv/settings/security) (currently requires a phone number).
3. [Register a new Application in the Twitch Developer Console](https://dev.twitch.tv/console/apps/create).
These settings will do (name can be anything, we don't use OAuth, but a redirect url is required; localhost will do):
Some files were not shown because too many files have changed in this diff
Show More
Reference in New Issue
Block a user
Blocking a user prevents them from interacting with repositories, such as opening or commenting on pull requests or issues. Learn more about blocking a user.