diff --git a/.deepsource.toml b/.deepsource.toml
deleted file mode 100644
index e5ec308c..00000000
--- a/.deepsource.toml
+++ /dev/null
@@ -1,7 +0,0 @@
-version = 1
-
-[[analyzers]]
-name = "javascript"
-
- [analyzers.meta]
- environment = ["nodejs"]
\ No newline at end of file
diff --git a/.github/FUNDING.yml b/.github/FUNDING.yml
deleted file mode 100644
index 89951fe0..00000000
--- a/.github/FUNDING.yml
+++ /dev/null
@@ -1 +0,0 @@
-custom: https://boosty.to/wukko/donate
diff --git a/.github/ISSUE_TEMPLATE/bug-report.md b/.github/ISSUE_TEMPLATE/bug-report.md
deleted file mode 100644
index e5429401..00000000
--- a/.github/ISSUE_TEMPLATE/bug-report.md
+++ /dev/null
@@ -1,32 +0,0 @@
----
-name: bug report
-about: report an issue with downloads or something else
-title: ''
-labels: bug
-assignees: ''
-
----
-
-**bug description**
-a clear and concise description of what the bug is.
-
-**reproduction steps**
-steps to reproduce the behavior:
-1. go to '...'
-2. click on '....'
-3. download this video: **[link here]**
-4. see error
-
-**screenshots**
-if applicable, add screenshots or screen recordings to help explain your problem.
-
-**links**
-if applicable, add links that cause the issue. more = better.
-
-**platform**
-- OS [e.g. iOS, windows]
-- browser [e.g. chrome, safari, firefox]
-- version [e.g. 115]
-
-**additional context**
-add any other context about the problem here.
diff --git a/.github/ISSUE_TEMPLATE/feature-request.md b/.github/ISSUE_TEMPLATE/feature-request.md
deleted file mode 100644
index 18307f4f..00000000
--- a/.github/ISSUE_TEMPLATE/feature-request.md
+++ /dev/null
@@ -1,17 +0,0 @@
----
-name: feature request
-about: suggest a feature for cobalt
-title: ''
-labels: feature request
-assignees: ''
-
----
-
-**describe the feature you'd like to see**
-a clear and concise description of what you want to happen.
-
-**describe alternatives you've considered**
-a clear and concise description of any alternative solutions or features you've considered.
-
-**additional context**
-add any other context or screenshots about the feature request here.
diff --git a/.github/workflows/docker.yml b/.github/workflows/docker.yml
deleted file mode 100644
index 0d166c74..00000000
--- a/.github/workflows/docker.yml
+++ /dev/null
@@ -1,57 +0,0 @@
-name: Build Docker image
-
-on:
- workflow_dispatch:
-
-env:
- REGISTRY: ghcr.io
- IMAGE_NAME: ${{ github.repository }}
-
-jobs:
- build-and-push-image:
- runs-on: ubuntu-latest
- permissions:
- contents: read
- packages: write
-
- steps:
- - name: Checkout repository
- uses: actions/checkout@v4
- - name: Set up QEMU
- uses: docker/setup-qemu-action@v3
- - name: Set up Docker Buildx
- uses: docker/setup-buildx-action@v3
-
- - name: Log in to the Container registry
- uses: docker/login-action@v3
- with:
- registry: ${{ env.REGISTRY }}
- username: ${{ github.actor }}
- password: ${{ secrets.GITHUB_TOKEN }}
-
- - name: Get release metadata
- id: release-meta
- run: |
- version=$(cat package.json | jq -r .version)
- echo "commit_short=$(git rev-parse --short HEAD)" >> $GITHUB_OUTPUT
- echo "version=$version" >> $GITHUB_OUTPUT
- echo "major_version=$(echo "$version" | cut -d. -f1)" >> $GITHUB_OUTPUT
- - name: Extract metadata (tags, labels) for Docker
- id: meta
- uses: docker/metadata-action@v5
- with:
- tags: |
- type=raw,value=latest
- type=raw,value=${{ steps.release-meta.outputs.version }}
- type=raw,value=${{ steps.release-meta.outputs.major_version }}
- type=raw,value=${{ steps.release-meta.outputs.version }}-${{ steps.release-meta.outputs.commit_short }}
- images: ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}
-
- - name: Build and push Docker image
- uses: docker/build-push-action@v5
- with:
- context: .
- platforms: linux/amd64,linux/arm64,linux/arm/v7
- push: true
- tags: ${{ steps.meta.outputs.tags }}
- labels: ${{ steps.meta.outputs.labels }}
diff --git a/.gitignore b/.gitignore
deleted file mode 100644
index a21273d6..00000000
--- a/.gitignore
+++ /dev/null
@@ -1,26 +0,0 @@
-# os stuff
-.DS_Store
-desktop.ini
-
-# npm
-node_modules
-package-lock.json
-
-# secrets
-.env
-
-# page build
-min
-build
-
-# stuff i already made but delayed
-future
-
-# docker
-docker-compose.yml
-
-# vscode
-.vscode
-
-# cookie file
-cookies.json
diff --git a/Dockerfile b/Dockerfile
deleted file mode 100644
index 4eee25b9..00000000
--- a/Dockerfile
+++ /dev/null
@@ -1,15 +0,0 @@
-FROM node:18-bullseye-slim
-WORKDIR /app
-
-RUN apt-get update
-RUN apt-get install -y git
-RUN rm -rf /var/lib/apt/lists/*
-
-COPY package*.json ./
-RUN npm install
-
-RUN git clone -n https://github.com/imputnet/cobalt.git --depth 1 && mv cobalt/.git ./ && rm -rf cobalt
-
-COPY . .
-EXPOSE 9000
-CMD [ "node", "src/cobalt" ]
diff --git a/LICENSE b/LICENSE
deleted file mode 100644
index f79473af..00000000
--- a/LICENSE
+++ /dev/null
@@ -1,661 +0,0 @@
- GNU AFFERO GENERAL PUBLIC LICENSE
- Version 3, 19 November 2007
-
- Copyright (C) 2007 Free Software Foundation, Inc.
- Everyone is permitted to copy and distribute verbatim copies
- of this license document, but changing it is not allowed.
-
- Preamble
-
- The GNU Affero General Public License is a free, copyleft license for
-software and other kinds of works, specifically designed to ensure
-cooperation with the community in the case of network server software.
-
- The licenses for most software and other practical works are designed
-to take away your freedom to share and change the works. By contrast,
-our General Public Licenses are intended to guarantee your freedom to
-share and change all versions of a program--to make sure it remains free
-software for all its users.
-
- When we speak of free software, we are referring to freedom, not
-price. Our General Public Licenses are designed to make sure that you
-have the freedom to distribute copies of free software (and charge for
-them if you wish), that you receive source code or can get it if you
-want it, that you can change the software or use pieces of it in new
-free programs, and that you know you can do these things.
-
- Developers that use our General Public Licenses protect your rights
-with two steps: (1) assert copyright on the software, and (2) offer
-you this License which gives you legal permission to copy, distribute
-and/or modify the software.
-
- A secondary benefit of defending all users' freedom is that
-improvements made in alternate versions of the program, if they
-receive widespread use, become available for other developers to
-incorporate. Many developers of free software are heartened and
-encouraged by the resulting cooperation. However, in the case of
-software used on network servers, this result may fail to come about.
-The GNU General Public License permits making a modified version and
-letting the public access it on a server without ever releasing its
-source code to the public.
-
- The GNU Affero General Public License is designed specifically to
-ensure that, in such cases, the modified source code becomes available
-to the community. It requires the operator of a network server to
-provide the source code of the modified version running there to the
-users of that server. Therefore, public use of a modified version, on
-a publicly accessible server, gives the public access to the source
-code of the modified version.
-
- An older license, called the Affero General Public License and
-published by Affero, was designed to accomplish similar goals. This is
-a different license, not a version of the Affero GPL, but Affero has
-released a new version of the Affero GPL which permits relicensing under
-this license.
-
- The precise terms and conditions for copying, distribution and
-modification follow.
-
- TERMS AND CONDITIONS
-
- 0. Definitions.
-
- "This License" refers to version 3 of the GNU Affero General Public License.
-
- "Copyright" also means copyright-like laws that apply to other kinds of
-works, such as semiconductor masks.
-
- "The Program" refers to any copyrightable work licensed under this
-License. Each licensee is addressed as "you". "Licensees" and
-"recipients" may be individuals or organizations.
-
- To "modify" a work means to copy from or adapt all or part of the work
-in a fashion requiring copyright permission, other than the making of an
-exact copy. The resulting work is called a "modified version" of the
-earlier work or a work "based on" the earlier work.
-
- A "covered work" means either the unmodified Program or a work based
-on the Program.
-
- To "propagate" a work means to do anything with it that, without
-permission, would make you directly or secondarily liable for
-infringement under applicable copyright law, except executing it on a
-computer or modifying a private copy. Propagation includes copying,
-distribution (with or without modification), making available to the
-public, and in some countries other activities as well.
-
- To "convey" a work means any kind of propagation that enables other
-parties to make or receive copies. Mere interaction with a user through
-a computer network, with no transfer of a copy, is not conveying.
-
- An interactive user interface displays "Appropriate Legal Notices"
-to the extent that it includes a convenient and prominently visible
-feature that (1) displays an appropriate copyright notice, and (2)
-tells the user that there is no warranty for the work (except to the
-extent that warranties are provided), that licensees may convey the
-work under this License, and how to view a copy of this License. If
-the interface presents a list of user commands or options, such as a
-menu, a prominent item in the list meets this criterion.
-
- 1. Source Code.
-
- The "source code" for a work means the preferred form of the work
-for making modifications to it. "Object code" means any non-source
-form of a work.
-
- A "Standard Interface" means an interface that either is an official
-standard defined by a recognized standards body, or, in the case of
-interfaces specified for a particular programming language, one that
-is widely used among developers working in that language.
-
- The "System Libraries" of an executable work include anything, other
-than the work as a whole, that (a) is included in the normal form of
-packaging a Major Component, but which is not part of that Major
-Component, and (b) serves only to enable use of the work with that
-Major Component, or to implement a Standard Interface for which an
-implementation is available to the public in source code form. A
-"Major Component", in this context, means a major essential component
-(kernel, window system, and so on) of the specific operating system
-(if any) on which the executable work runs, or a compiler used to
-produce the work, or an object code interpreter used to run it.
-
- The "Corresponding Source" for a work in object code form means all
-the source code needed to generate, install, and (for an executable
-work) run the object code and to modify the work, including scripts to
-control those activities. However, it does not include the work's
-System Libraries, or general-purpose tools or generally available free
-programs which are used unmodified in performing those activities but
-which are not part of the work. For example, Corresponding Source
-includes interface definition files associated with source files for
-the work, and the source code for shared libraries and dynamically
-linked subprograms that the work is specifically designed to require,
-such as by intimate data communication or control flow between those
-subprograms and other parts of the work.
-
- The Corresponding Source need not include anything that users
-can regenerate automatically from other parts of the Corresponding
-Source.
-
- The Corresponding Source for a work in source code form is that
-same work.
-
- 2. Basic Permissions.
-
- All rights granted under this License are granted for the term of
-copyright on the Program, and are irrevocable provided the stated
-conditions are met. This License explicitly affirms your unlimited
-permission to run the unmodified Program. The output from running a
-covered work is covered by this License only if the output, given its
-content, constitutes a covered work. This License acknowledges your
-rights of fair use or other equivalent, as provided by copyright law.
-
- You may make, run and propagate covered works that you do not
-convey, without conditions so long as your license otherwise remains
-in force. You may convey covered works to others for the sole purpose
-of having them make modifications exclusively for you, or provide you
-with facilities for running those works, provided that you comply with
-the terms of this License in conveying all material for which you do
-not control copyright. Those thus making or running the covered works
-for you must do so exclusively on your behalf, under your direction
-and control, on terms that prohibit them from making any copies of
-your copyrighted material outside their relationship with you.
-
- Conveying under any other circumstances is permitted solely under
-the conditions stated below. Sublicensing is not allowed; section 10
-makes it unnecessary.
-
- 3. Protecting Users' Legal Rights From Anti-Circumvention Law.
-
- No covered work shall be deemed part of an effective technological
-measure under any applicable law fulfilling obligations under article
-11 of the WIPO copyright treaty adopted on 20 December 1996, or
-similar laws prohibiting or restricting circumvention of such
-measures.
-
- When you convey a covered work, you waive any legal power to forbid
-circumvention of technological measures to the extent such circumvention
-is effected by exercising rights under this License with respect to
-the covered work, and you disclaim any intention to limit operation or
-modification of the work as a means of enforcing, against the work's
-users, your or third parties' legal rights to forbid circumvention of
-technological measures.
-
- 4. Conveying Verbatim Copies.
-
- You may convey verbatim copies of the Program's source code as you
-receive it, in any medium, provided that you conspicuously and
-appropriately publish on each copy an appropriate copyright notice;
-keep intact all notices stating that this License and any
-non-permissive terms added in accord with section 7 apply to the code;
-keep intact all notices of the absence of any warranty; and give all
-recipients a copy of this License along with the Program.
-
- You may charge any price or no price for each copy that you convey,
-and you may offer support or warranty protection for a fee.
-
- 5. Conveying Modified Source Versions.
-
- You may convey a work based on the Program, or the modifications to
-produce it from the Program, in the form of source code under the
-terms of section 4, provided that you also meet all of these conditions:
-
- a) The work must carry prominent notices stating that you modified
- it, and giving a relevant date.
-
- b) The work must carry prominent notices stating that it is
- released under this License and any conditions added under section
- 7. This requirement modifies the requirement in section 4 to
- "keep intact all notices".
-
- c) You must license the entire work, as a whole, under this
- License to anyone who comes into possession of a copy. This
- License will therefore apply, along with any applicable section 7
- additional terms, to the whole of the work, and all its parts,
- regardless of how they are packaged. This License gives no
- permission to license the work in any other way, but it does not
- invalidate such permission if you have separately received it.
-
- d) If the work has interactive user interfaces, each must display
- Appropriate Legal Notices; however, if the Program has interactive
- interfaces that do not display Appropriate Legal Notices, your
- work need not make them do so.
-
- A compilation of a covered work with other separate and independent
-works, which are not by their nature extensions of the covered work,
-and which are not combined with it such as to form a larger program,
-in or on a volume of a storage or distribution medium, is called an
-"aggregate" if the compilation and its resulting copyright are not
-used to limit the access or legal rights of the compilation's users
-beyond what the individual works permit. Inclusion of a covered work
-in an aggregate does not cause this License to apply to the other
-parts of the aggregate.
-
- 6. Conveying Non-Source Forms.
-
- You may convey a covered work in object code form under the terms
-of sections 4 and 5, provided that you also convey the
-machine-readable Corresponding Source under the terms of this License,
-in one of these ways:
-
- a) Convey the object code in, or embodied in, a physical product
- (including a physical distribution medium), accompanied by the
- Corresponding Source fixed on a durable physical medium
- customarily used for software interchange.
-
- b) Convey the object code in, or embodied in, a physical product
- (including a physical distribution medium), accompanied by a
- written offer, valid for at least three years and valid for as
- long as you offer spare parts or customer support for that product
- model, to give anyone who possesses the object code either (1) a
- copy of the Corresponding Source for all the software in the
- product that is covered by this License, on a durable physical
- medium customarily used for software interchange, for a price no
- more than your reasonable cost of physically performing this
- conveying of source, or (2) access to copy the
- Corresponding Source from a network server at no charge.
-
- c) Convey individual copies of the object code with a copy of the
- written offer to provide the Corresponding Source. This
- alternative is allowed only occasionally and noncommercially, and
- only if you received the object code with such an offer, in accord
- with subsection 6b.
-
- d) Convey the object code by offering access from a designated
- place (gratis or for a charge), and offer equivalent access to the
- Corresponding Source in the same way through the same place at no
- further charge. You need not require recipients to copy the
- Corresponding Source along with the object code. If the place to
- copy the object code is a network server, the Corresponding Source
- may be on a different server (operated by you or a third party)
- that supports equivalent copying facilities, provided you maintain
- clear directions next to the object code saying where to find the
- Corresponding Source. Regardless of what server hosts the
- Corresponding Source, you remain obligated to ensure that it is
- available for as long as needed to satisfy these requirements.
-
- e) Convey the object code using peer-to-peer transmission, provided
- you inform other peers where the object code and Corresponding
- Source of the work are being offered to the general public at no
- charge under subsection 6d.
-
- A separable portion of the object code, whose source code is excluded
-from the Corresponding Source as a System Library, need not be
-included in conveying the object code work.
-
- A "User Product" is either (1) a "consumer product", which means any
-tangible personal property which is normally used for personal, family,
-or household purposes, or (2) anything designed or sold for incorporation
-into a dwelling. In determining whether a product is a consumer product,
-doubtful cases shall be resolved in favor of coverage. For a particular
-product received by a particular user, "normally used" refers to a
-typical or common use of that class of product, regardless of the status
-of the particular user or of the way in which the particular user
-actually uses, or expects or is expected to use, the product. A product
-is a consumer product regardless of whether the product has substantial
-commercial, industrial or non-consumer uses, unless such uses represent
-the only significant mode of use of the product.
-
- "Installation Information" for a User Product means any methods,
-procedures, authorization keys, or other information required to install
-and execute modified versions of a covered work in that User Product from
-a modified version of its Corresponding Source. The information must
-suffice to ensure that the continued functioning of the modified object
-code is in no case prevented or interfered with solely because
-modification has been made.
-
- If you convey an object code work under this section in, or with, or
-specifically for use in, a User Product, and the conveying occurs as
-part of a transaction in which the right of possession and use of the
-User Product is transferred to the recipient in perpetuity or for a
-fixed term (regardless of how the transaction is characterized), the
-Corresponding Source conveyed under this section must be accompanied
-by the Installation Information. But this requirement does not apply
-if neither you nor any third party retains the ability to install
-modified object code on the User Product (for example, the work has
-been installed in ROM).
-
- The requirement to provide Installation Information does not include a
-requirement to continue to provide support service, warranty, or updates
-for a work that has been modified or installed by the recipient, or for
-the User Product in which it has been modified or installed. Access to a
-network may be denied when the modification itself materially and
-adversely affects the operation of the network or violates the rules and
-protocols for communication across the network.
-
- Corresponding Source conveyed, and Installation Information provided,
-in accord with this section must be in a format that is publicly
-documented (and with an implementation available to the public in
-source code form), and must require no special password or key for
-unpacking, reading or copying.
-
- 7. Additional Terms.
-
- "Additional permissions" are terms that supplement the terms of this
-License by making exceptions from one or more of its conditions.
-Additional permissions that are applicable to the entire Program shall
-be treated as though they were included in this License, to the extent
-that they are valid under applicable law. If additional permissions
-apply only to part of the Program, that part may be used separately
-under those permissions, but the entire Program remains governed by
-this License without regard to the additional permissions.
-
- When you convey a copy of a covered work, you may at your option
-remove any additional permissions from that copy, or from any part of
-it. (Additional permissions may be written to require their own
-removal in certain cases when you modify the work.) You may place
-additional permissions on material, added by you to a covered work,
-for which you have or can give appropriate copyright permission.
-
- Notwithstanding any other provision of this License, for material you
-add to a covered work, you may (if authorized by the copyright holders of
-that material) supplement the terms of this License with terms:
-
- a) Disclaiming warranty or limiting liability differently from the
- terms of sections 15 and 16 of this License; or
-
- b) Requiring preservation of specified reasonable legal notices or
- author attributions in that material or in the Appropriate Legal
- Notices displayed by works containing it; or
-
- c) Prohibiting misrepresentation of the origin of that material, or
- requiring that modified versions of such material be marked in
- reasonable ways as different from the original version; or
-
- d) Limiting the use for publicity purposes of names of licensors or
- authors of the material; or
-
- e) Declining to grant rights under trademark law for use of some
- trade names, trademarks, or service marks; or
-
- f) Requiring indemnification of licensors and authors of that
- material by anyone who conveys the material (or modified versions of
- it) with contractual assumptions of liability to the recipient, for
- any liability that these contractual assumptions directly impose on
- those licensors and authors.
-
- All other non-permissive additional terms are considered "further
-restrictions" within the meaning of section 10. If the Program as you
-received it, or any part of it, contains a notice stating that it is
-governed by this License along with a term that is a further
-restriction, you may remove that term. If a license document contains
-a further restriction but permits relicensing or conveying under this
-License, you may add to a covered work material governed by the terms
-of that license document, provided that the further restriction does
-not survive such relicensing or conveying.
-
- If you add terms to a covered work in accord with this section, you
-must place, in the relevant source files, a statement of the
-additional terms that apply to those files, or a notice indicating
-where to find the applicable terms.
-
- Additional terms, permissive or non-permissive, may be stated in the
-form of a separately written license, or stated as exceptions;
-the above requirements apply either way.
-
- 8. Termination.
-
- You may not propagate or modify a covered work except as expressly
-provided under this License. Any attempt otherwise to propagate or
-modify it is void, and will automatically terminate your rights under
-this License (including any patent licenses granted under the third
-paragraph of section 11).
-
- However, if you cease all violation of this License, then your
-license from a particular copyright holder is reinstated (a)
-provisionally, unless and until the copyright holder explicitly and
-finally terminates your license, and (b) permanently, if the copyright
-holder fails to notify you of the violation by some reasonable means
-prior to 60 days after the cessation.
-
- Moreover, your license from a particular copyright holder is
-reinstated permanently if the copyright holder notifies you of the
-violation by some reasonable means, this is the first time you have
-received notice of violation of this License (for any work) from that
-copyright holder, and you cure the violation prior to 30 days after
-your receipt of the notice.
-
- Termination of your rights under this section does not terminate the
-licenses of parties who have received copies or rights from you under
-this License. If your rights have been terminated and not permanently
-reinstated, you do not qualify to receive new licenses for the same
-material under section 10.
-
- 9. Acceptance Not Required for Having Copies.
-
- You are not required to accept this License in order to receive or
-run a copy of the Program. Ancillary propagation of a covered work
-occurring solely as a consequence of using peer-to-peer transmission
-to receive a copy likewise does not require acceptance. However,
-nothing other than this License grants you permission to propagate or
-modify any covered work. These actions infringe copyright if you do
-not accept this License. Therefore, by modifying or propagating a
-covered work, you indicate your acceptance of this License to do so.
-
- 10. Automatic Licensing of Downstream Recipients.
-
- Each time you convey a covered work, the recipient automatically
-receives a license from the original licensors, to run, modify and
-propagate that work, subject to this License. You are not responsible
-for enforcing compliance by third parties with this License.
-
- An "entity transaction" is a transaction transferring control of an
-organization, or substantially all assets of one, or subdividing an
-organization, or merging organizations. If propagation of a covered
-work results from an entity transaction, each party to that
-transaction who receives a copy of the work also receives whatever
-licenses to the work the party's predecessor in interest had or could
-give under the previous paragraph, plus a right to possession of the
-Corresponding Source of the work from the predecessor in interest, if
-the predecessor has it or can get it with reasonable efforts.
-
- You may not impose any further restrictions on the exercise of the
-rights granted or affirmed under this License. For example, you may
-not impose a license fee, royalty, or other charge for exercise of
-rights granted under this License, and you may not initiate litigation
-(including a cross-claim or counterclaim in a lawsuit) alleging that
-any patent claim is infringed by making, using, selling, offering for
-sale, or importing the Program or any portion of it.
-
- 11. Patents.
-
- A "contributor" is a copyright holder who authorizes use under this
-License of the Program or a work on which the Program is based. The
-work thus licensed is called the contributor's "contributor version".
-
- A contributor's "essential patent claims" are all patent claims
-owned or controlled by the contributor, whether already acquired or
-hereafter acquired, that would be infringed by some manner, permitted
-by this License, of making, using, or selling its contributor version,
-but do not include claims that would be infringed only as a
-consequence of further modification of the contributor version. For
-purposes of this definition, "control" includes the right to grant
-patent sublicenses in a manner consistent with the requirements of
-this License.
-
- Each contributor grants you a non-exclusive, worldwide, royalty-free
-patent license under the contributor's essential patent claims, to
-make, use, sell, offer for sale, import and otherwise run, modify and
-propagate the contents of its contributor version.
-
- In the following three paragraphs, a "patent license" is any express
-agreement or commitment, however denominated, not to enforce a patent
-(such as an express permission to practice a patent or covenant not to
-sue for patent infringement). To "grant" such a patent license to a
-party means to make such an agreement or commitment not to enforce a
-patent against the party.
-
- If you convey a covered work, knowingly relying on a patent license,
-and the Corresponding Source of the work is not available for anyone
-to copy, free of charge and under the terms of this License, through a
-publicly available network server or other readily accessible means,
-then you must either (1) cause the Corresponding Source to be so
-available, or (2) arrange to deprive yourself of the benefit of the
-patent license for this particular work, or (3) arrange, in a manner
-consistent with the requirements of this License, to extend the patent
-license to downstream recipients. "Knowingly relying" means you have
-actual knowledge that, but for the patent license, your conveying the
-covered work in a country, or your recipient's use of the covered work
-in a country, would infringe one or more identifiable patents in that
-country that you have reason to believe are valid.
-
- If, pursuant to or in connection with a single transaction or
-arrangement, you convey, or propagate by procuring conveyance of, a
-covered work, and grant a patent license to some of the parties
-receiving the covered work authorizing them to use, propagate, modify
-or convey a specific copy of the covered work, then the patent license
-you grant is automatically extended to all recipients of the covered
-work and works based on it.
-
- A patent license is "discriminatory" if it does not include within
-the scope of its coverage, prohibits the exercise of, or is
-conditioned on the non-exercise of one or more of the rights that are
-specifically granted under this License. You may not convey a covered
-work if you are a party to an arrangement with a third party that is
-in the business of distributing software, under which you make payment
-to the third party based on the extent of your activity of conveying
-the work, and under which the third party grants, to any of the
-parties who would receive the covered work from you, a discriminatory
-patent license (a) in connection with copies of the covered work
-conveyed by you (or copies made from those copies), or (b) primarily
-for and in connection with specific products or compilations that
-contain the covered work, unless you entered into that arrangement,
-or that patent license was granted, prior to 28 March 2007.
-
- Nothing in this License shall be construed as excluding or limiting
-any implied license or other defenses to infringement that may
-otherwise be available to you under applicable patent law.
-
- 12. No Surrender of Others' Freedom.
-
- If conditions are imposed on you (whether by court order, agreement or
-otherwise) that contradict the conditions of this License, they do not
-excuse you from the conditions of this License. If you cannot convey a
-covered work so as to satisfy simultaneously your obligations under this
-License and any other pertinent obligations, then as a consequence you may
-not convey it at all. For example, if you agree to terms that obligate you
-to collect a royalty for further conveying from those to whom you convey
-the Program, the only way you could satisfy both those terms and this
-License would be to refrain entirely from conveying the Program.
-
- 13. Remote Network Interaction; Use with the GNU General Public License.
-
- Notwithstanding any other provision of this License, if you modify the
-Program, your modified version must prominently offer all users
-interacting with it remotely through a computer network (if your version
-supports such interaction) an opportunity to receive the Corresponding
-Source of your version by providing access to the Corresponding Source
-from a network server at no charge, through some standard or customary
-means of facilitating copying of software. This Corresponding Source
-shall include the Corresponding Source for any work covered by version 3
-of the GNU General Public License that is incorporated pursuant to the
-following paragraph.
-
- Notwithstanding any other provision of this License, you have
-permission to link or combine any covered work with a work licensed
-under version 3 of the GNU General Public License into a single
-combined work, and to convey the resulting work. The terms of this
-License will continue to apply to the part which is the covered work,
-but the work with which it is combined will remain governed by version
-3 of the GNU General Public License.
-
- 14. Revised Versions of this License.
-
- The Free Software Foundation may publish revised and/or new versions of
-the GNU Affero General Public License from time to time. Such new versions
-will be similar in spirit to the present version, but may differ in detail to
-address new problems or concerns.
-
- Each version is given a distinguishing version number. If the
-Program specifies that a certain numbered version of the GNU Affero General
-Public License "or any later version" applies to it, you have the
-option of following the terms and conditions either of that numbered
-version or of any later version published by the Free Software
-Foundation. If the Program does not specify a version number of the
-GNU Affero General Public License, you may choose any version ever published
-by the Free Software Foundation.
-
- If the Program specifies that a proxy can decide which future
-versions of the GNU Affero General Public License can be used, that proxy's
-public statement of acceptance of a version permanently authorizes you
-to choose that version for the Program.
-
- Later license versions may give you additional or different
-permissions. However, no additional obligations are imposed on any
-author or copyright holder as a result of your choosing to follow a
-later version.
-
- 15. Disclaimer of Warranty.
-
- THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY
-APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT
-HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY
-OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO,
-THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
-PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM
-IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF
-ALL NECESSARY SERVICING, REPAIR OR CORRECTION.
-
- 16. Limitation of Liability.
-
- IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
-WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MODIFIES AND/OR CONVEYS
-THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY
-GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE
-USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF
-DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD
-PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS),
-EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF
-SUCH DAMAGES.
-
- 17. Interpretation of Sections 15 and 16.
-
- If the disclaimer of warranty and limitation of liability provided
-above cannot be given local legal effect according to their terms,
-reviewing courts shall apply local law that most closely approximates
-an absolute waiver of all civil liability in connection with the
-Program, unless a warranty or assumption of liability accompanies a
-copy of the Program in return for a fee.
-
- END OF TERMS AND CONDITIONS
-
- How to Apply These Terms to Your New Programs
-
- If you develop a new program, and you want it to be of the greatest
-possible use to the public, the best way to achieve this is to make it
-free software which everyone can redistribute and change under these terms.
-
- To do so, attach the following notices to the program. It is safest
-to attach them to the start of each source file to most effectively
-state the exclusion of warranty; and each file should have at least
-the "copyright" line and a pointer to where the full notice is found.
-
- cobalt is possibly the nicest social media downloader out there.
- Copyright (C) 2022 wukko
-
- This program is free software: you can redistribute it and/or modify
- it under the terms of the GNU Affero General Public License as published by
- the Free Software Foundation, either version 3 of the License, or
- (at your option) any later version.
-
- This program is distributed in the hope that it will be useful,
- but WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- GNU Affero General Public License for more details.
-
- You should have received a copy of the GNU Affero General Public License
- along with this program. If not, see .
-
-Also add information on how to contact you by electronic and paper mail.
-
- If your software can interact with users remotely through a computer
-network, you should also make sure that it provides a way for users to
-get its source. For example, if your program is a web application, its
-interface could display a "Source" link that leads users to an archive
-of the code. There are many ways you could offer source, and different
-solutions will be better for different programs; see section 13 for the
-specific requirements.
-
- You should also get your employer (if you work as a programmer) or school,
-if any, to sign a "copyright disclaimer" for the program, if necessary.
-For more information on this, and how to apply and follow the GNU AGPL, see
-.
diff --git a/PAK1.PAK b/PAK1.PAK
new file mode 100644
index 00000000..cac2fabe
Binary files /dev/null and b/PAK1.PAK differ
diff --git a/README.md b/README.md
deleted file mode 100644
index 8374817a..00000000
--- a/README.md
+++ /dev/null
@@ -1,128 +0,0 @@
-# cobalt
-best way to save what you love: [cobalt.tools](https://cobalt.tools/)
-
- pattern background")
-
-## what's cobalt?
-cobalt is a media downloader that doesn't piss you off. it's fast, friendly, and doesn't have any bullshit that modern web is filled with: ***no ads, trackers, or invasive analytics***.
-
-paste the link, get the file, move on. it's that simple. just how it should be.
-
-## supported services
-this list is not final and keeps expanding over time. if support for a service you want is missing, create an issue (or a pull request 👀).
-
-| service | video + audio | only audio | only video | metadata | rich file names |
-| :-------- | :-----------: | :--------: | :--------: | :------: | :-------------: |
-| bilibili.com & bilibili.tv | ✅ | ✅ | ✅ | ➖ | ➖ |
-| dailymotion | ✅ | ✅ | ✅ | ✅ | ✅ |
-| instagram posts & stories | ✅ | ✅ | ✅ | ➖ | ➖ |
-| instagram reels | ✅ | ✅ | ✅ | ➖ | ➖ |
-| ok video | ✅ | ❌ | ❌ | ✅ | ✅ |
-| pinterest | ✅ | ✅ | ✅ | ➖ | ➖ |
-| reddit | ✅ | ✅ | ✅ | ❌ | ❌ |
-| rutube | ✅ | ✅ | ✅ | ✅ | ✅ |
-| soundcloud | ➖ | ✅ | ➖ | ✅ | ✅ |
-| streamable | ✅ | ✅ | ✅ | ➖ | ➖ |
-| tiktok | ✅ | ✅ | ✅ | ❌ | ❌ |
-| tumblr | ✅ | ✅ | ✅ | ➖ | ➖ |
-| twitch clips | ✅ | ✅ | ✅ | ✅ | ✅ |
-| twitter/x | ✅ | ✅ | ✅ | ➖ | ➖ |
-| vimeo | ✅ | ✅ | ✅ | ✅ | ✅ |
-| vine archive | ✅ | ✅ | ✅ | ➖ | ➖ |
-| vk videos & clips | ✅ | ❌ | ❌ | ✅ | ✅ |
-| youtube videos, shorts & music | ✅ | ✅ | ✅ | ✅ | ✅ |
-
-| emoji | meaning |
-| :-----: | :---------------------- |
-| ✅ | supported |
-| ➖ | impossible/unreasonable |
-| ❌ | not supported |
-
-### additional notes or features (per service)
-| service | notes or features |
-| :-------- | :----- |
-| instagram | supports photos, videos, and stories. lets you pick what to save from multi-media posts. |
-| pinterest | supports videos and stories. |
-| reddit | supports gifs and videos. |
-| soundcloud | supports private links. |
-| tiktok | supports videos with or without watermark, images from slideshow without watermark, and full (original) audios. |
-| twitter/x | lets you pick what to save from multi-media posts. may not be 100% reliable due to current management. |
-| vimeo | audio downloads are only available for dash. |
-| youtube | supports videos, music, and shorts. 8K, 4K, HDR, VR, and high FPS videos. rich metadata & dubs. h264/av1/vp9 codecs. |
-
-## cobalt api
-cobalt has an open api that you can use in your projects *for free~*. it's easy and straightforward to use, [check out the docs](/docs/api.md) to learn how to use it.
-
-✅ you can use the main api instance ([co.wuk.sh](https://co.wuk.sh/)) in your **personal** projects.
-❌ you cannot use the free api commercially (anywhere that's gated behind paywalls or ads). host your own instance for this.
-
-we reserve the right to restrict abusive/excessive access to the main instance api.
-
-## how to run your own instance
-if you want to run your own instance for whatever purpose, [follow this guide](/docs/run-an-instance.md).
-it's *highly* recommended to use a docker compose method unless you run for developing/debugging purposes.
-
-## sponsors
-cobalt is sponsored by [royalehosting.net](https://royalehosting.net/), all main instances are currently hosted on their network :)
-
-## ethics and disclaimer
-cobalt is a tool for easing content downloads from internet and takes ***zero liability***. you are responsible for what you download, how you use and distribute that content. please be mindful when using content of others and always credit original creators. fair use and credits benefit everyone.
-
-cobalt is ***NOT*** a piracy tool and cannot be used as such. it can only download free, publicly accessible content. such content can be easily downloaded through any browser's dev tools. pressing one button is easier, so i made a convenient, ad-less tool for such repeated actions.
-
-## cobalt license
-cobalt code is licensed under [AGPL-3.0](/LICENSE).
-
-cobalt branding, mascots, and other related assets included in the repo are ***copyrighted*** and not covered by the AGPL-3.0 license. you ***cannot*** use them under same terms.
-
-you are allowed to host an ***unmodified*** instance of cobalt with branding, but this ***does not*** give you permission to use it anywhere else, or make derivatives of it in any way.
-
-### notes:
-- mascots and other assets are a part of the branding.
-
-- when making an alternative version of the project, please replace or remove all branding (including the name).
-
-- you **must** link the original repo when using any parts of code (such as using separate processing modules in your project) or forking the project.
-
-- if you make a modified version of cobalt, the codebase **must** be published under the same license (according to AGPL-3.0).
-
-## 3rd party licenses
-- [Fluent Emoji by Microsoft](https://github.com/microsoft/fluentui-emoji) (used in cobalt) is under [MIT](https://github.com/microsoft/fluentui-emoji/blob/main/LICENSE) license.
-- [Noto Sans Mono](https://fonts.google.com/noto/specimen/Noto+Sans+Mono/) fonts (used in cobalt) are licensed under the [OFL](https://fonts.google.com/noto/specimen/Noto+Sans+Mono/about) license.
-- many update banners were taken from [tenor.com](https://tenor.com/).
-
-## acknowledgements
-### ffmpeg
-cobalt heavily relies on ffmpeg for converting and merging media files. it's an absolutely amazing piece of software offered for anyone for free, yet doesn't receive as much credit as it should.
-
-you can [support ffmpeg here](https://ffmpeg.org/donations.html)!
-
-#### ffmpeg-static
-we use [ffmpeg-static](https://github.com/eugeneware/ffmpeg-static) to get binaries for ffmpeg depending on the platform.
-
-you can support the developer via various methods listed on their github page! (linked above)
-
-### youtube.js
-cobalt relies on [youtube.js](https://github.com/LuanRT/YouTube.js) for interacting with the innertube api, it wouldn't have been possible without it.
-
-you can support the developer via various methods listed on their github page! (linked above)
-
-### many others
-cobalt also depends on:
-
-- [content-disposition-header](https://www.npmjs.com/package/content-disposition-header) to simplify the provision of `content-disposition` headers.
-- [cors](https://www.npmjs.com/package/cors) to manage cross-origin resource sharing within expressjs.
-- [dotenv](https://www.npmjs.com/package/dotenv) to load environment variables from the `.env` file.
-- [esbuild](https://www.npmjs.com/package/esbuild) to minify the frontend files.
-- [express](https://www.npmjs.com/package/express) as the backbone of cobalt servers.
-- [express-rate-limit](https://www.npmjs.com/package/express-rate-limit) to rate limit api endpoints.
-- [hls-parser](https://www.npmjs.com/package/hls-parser) to parse `m3u8` playlists for certain services.
-- [ipaddr.js](https://www.npmjs.com/package/ipaddr.js) to parse ip addresses (for rate limiting).
-- [nanoid](https://www.npmjs.com/package/nanoid) to generate unique (temporary) identifiers for each requested stream.
-- [node-cache](https://www.npmjs.com/package/node-cache) to cache stream info in server ram for a limited amount of time.
-- [psl](https://www.npmjs.com/package/psl) as the domain name parser.
-- [set-cookie-parser](https://www.npmjs.com/package/set-cookie-parser) to parse cookies that cobalt receives from certain services.
-- [undici](https://www.npmjs.com/package/undici) for making http requests.
-- [url-pattern](https://www.npmjs.com/package/url-pattern) to match provided links with supported patterns.
-
-...and many other packages that these packages rely on.
diff --git a/docs/api.md b/docs/api.md
deleted file mode 100644
index 57509669..00000000
--- a/docs/api.md
+++ /dev/null
@@ -1,77 +0,0 @@
-# cobalt api documentation
-this document provides info about methods and acceptable variables for all cobalt api requests.
-
-```
-👍 you can use co.wuk.sh instance in your projects for free, just don't be an asshole.
-```
-
-## POST: `/api/json`
-cobalt's main processing endpoint.
-
-request body type: `application/json`
-response body type: `application/json`
-
-```
-⚠️ you must include Accept and Content-Type headers with every POST /api/json request.
-
-Accept: application/json
-Content-Type: application/json
-```
-
-### request body variables
-| key | type | variables | default | description |
-|:------------------|:----------|:-----------------------------------|:----------|:--------------------------------------------------------------------------------|
-| `url` | `string` | URL encoded as URI | `null` | **must** be included in every request. |
-| `vCodec` | `string` | `h264 / av1 / vp9` | `h264` | applies only to youtube downloads. `h264` is recommended for phones. |
-| `vQuality` | `string` | `144 / ... / 2160 / max` | `720` | `720` quality is recommended for phones. |
-| `aFormat` | `string` | `best / mp3 / ogg / wav / opus` | `mp3` | |
-| `filenamePattern` | `string` | `classic / pretty / basic / nerdy` | `classic` | changes the way files are named. previews can be seen in the web app. |
-| `isAudioOnly` | `boolean` | `true / false` | `false` | |
-| `isTTFullAudio` | `boolean` | `true / false` | `false` | enables download of original sound used in a tiktok video. |
-| `isAudioMuted` | `boolean` | `true / false` | `false` | disables audio track in video downloads. |
-| `dubLang` | `boolean` | `true / false` | `false` | backend uses Accept-Language header for youtube video audio tracks when `true`. |
-| `disableMetadata` | `boolean` | `true / false` | `false` | disables file metadata when set to `true`. |
-| `twitterGif` | `boolean` | `true / false` | `false` | changes whether twitter gifs are converted to .gif |
-| `tiktokH265` | `boolean` | `true / false` | `false` | changes whether 1080p h265 videos are preferred or not. |
-
-### response body variables
-| key | type | variables |
-|:-------------|:---------|:------------------------------------------------------------|
-| `status` | `string` | `error / redirect / stream / success / rate-limit / picker` |
-| `text` | `string` | various text, mostly used for errors |
-| `url` | `string` | direct link to a file or a link to cobalt's live render |
-| `pickerType` | `string` | `various / images` |
-| `picker` | `array` | array of picker items |
-| `audio` | `string` | direct link to a file or a link to cobalt's live render |
-
-### picker item variables
-item type: `object`
-
-| key | type | variables | description |
-|:--------|:---------|:--------------------------------------------------------|:---------------------------------------|
-| `type` | `string` | `video` | used only if `pickerType`is `various`. |
-| `url` | `string` | direct link to a file or a link to cobalt's live render | |
-| `thumb` | `string` | item thumbnail that's displayed in the picker | used only for `video` type. |
-
-## GET: `/api/stream`
-cobalt's live render (or stream) endpoint. usually, you will receive a url to this endpoint
-from a successful call to `/api/json`. however, the parameters passed to it are **opaque**
-and **unmodifiable** from your (the api client's) perspective, and can change between versions.
-
-therefore you don't need to worry about what they mean - but if you really want to know, you can
-[read the source code](/src/modules/stream/manage.js).
-
-## GET: `/api/serverInfo`
-returns current basic server info.
-response body type: `application/json`
-
-### response body variables
-| key | type | variables |
-|:------------|:---------|:------------------|
-| `version` | `string` | cobalt version |
-| `commit` | `string` | git commit |
-| `branch` | `string` | git branch |
-| `name` | `string` | server name |
-| `url` | `string` | server url |
-| `cors` | `int` | cors status |
-| `startTime` | `string` | server start time |
diff --git a/docs/examples/cookies.example.json b/docs/examples/cookies.example.json
deleted file mode 100644
index 73f3378d..00000000
--- a/docs/examples/cookies.example.json
+++ /dev/null
@@ -1,14 +0,0 @@
-{
- "instagram": [
- "mid=; ig_did=; csrftoken=; ds_user_id=; sessionid="
- ],
- "instagram_bearer": [
- "token=", "token=IGT:2:"
- ],
- "reddit": [
- "client_id=; client_secret=; refresh_token="
- ],
- "twitter": [
- "auth_token=; ct0="
- ]
-}
diff --git a/docs/examples/docker-compose.example.yml b/docs/examples/docker-compose.example.yml
deleted file mode 100644
index 24212ae4..00000000
--- a/docs/examples/docker-compose.example.yml
+++ /dev/null
@@ -1,64 +0,0 @@
-version: '3.5'
-
-services:
- cobalt-api:
- image: ghcr.io/imputnet/cobalt:7
- restart: unless-stopped
- container_name: cobalt-api
-
- init: true
-
- # if container doesn't run detached on your machine, uncomment the next line
- #tty: true
-
- ports:
- - 9000:9000/tcp
- # if you're using a reverse proxy, uncomment the next line and remove the one above (9000:9000/tcp):
- #- 127.0.0.1:9000:9000
-
- environment:
- # replace https://co.wuk.sh/ with your instance's target url in same format
- API_URL: "https://co.wuk.sh/"
- # replace eu-nl with your instance's distinctive name
- API_NAME: "eu-nl"
- # if you want to use cookies when fetching data from services, uncomment the next line and the lines under volume
- # COOKIE_PATH: "/cookies.json"
- # see docs/run-an-instance.md for more information
- labels:
- - com.centurylinklabs.watchtower.scope=cobalt
-
- # if you want to use cookies when fetching data from services, uncomment volumes and next line
- #volumes:
- #- ./cookies.json:/cookies.json
-
- cobalt-web:
- image: ghcr.io/imputnet/cobalt:7
- restart: unless-stopped
- container_name: cobalt-web
-
- init: true
-
- # if container doesn't run detached on your machine, uncomment the next line
- #tty: true
-
- ports:
- - 9001:9001/tcp
- # if you're using a reverse proxy, uncomment the next line and remove the one above (9001:9001/tcp):
- #- 127.0.0.1:9001:9001
-
- environment:
- # replace https://cobalt.tools/ with your instance's target url in same format
- WEB_URL: "https://cobalt.tools/"
- # replace https://co.wuk.sh/ with preferred api instance url
- API_URL: "https://co.wuk.sh/"
-
- labels:
- - com.centurylinklabs.watchtower.scope=cobalt
-
- # update the cobalt image automatically with watchtower
- watchtower:
- image: ghcr.io/containrrr/watchtower
- restart: unless-stopped
- command: --cleanup --scope cobalt --interval 900
- volumes:
- - /var/run/docker.sock:/var/run/docker.sock
diff --git a/docs/images/troubleshooting/clipboard/config.png b/docs/images/troubleshooting/clipboard/config.png
deleted file mode 100644
index b0c0a048..00000000
Binary files a/docs/images/troubleshooting/clipboard/config.png and /dev/null differ
diff --git a/docs/images/troubleshooting/clipboard/risk.png b/docs/images/troubleshooting/clipboard/risk.png
deleted file mode 100644
index 1948f0eb..00000000
Binary files a/docs/images/troubleshooting/clipboard/risk.png and /dev/null differ
diff --git a/docs/images/troubleshooting/clipboard/search.png b/docs/images/troubleshooting/clipboard/search.png
deleted file mode 100644
index 95684ff4..00000000
Binary files a/docs/images/troubleshooting/clipboard/search.png and /dev/null differ
diff --git a/docs/images/troubleshooting/clipboard/toggle.png b/docs/images/troubleshooting/clipboard/toggle.png
deleted file mode 100644
index 32060dc7..00000000
Binary files a/docs/images/troubleshooting/clipboard/toggle.png and /dev/null differ
diff --git a/docs/images/troubleshooting/clipboard/toggled.png b/docs/images/troubleshooting/clipboard/toggled.png
deleted file mode 100644
index 6afa0ace..00000000
Binary files a/docs/images/troubleshooting/clipboard/toggled.png and /dev/null differ
diff --git a/docs/run-an-instance.md b/docs/run-an-instance.md
deleted file mode 100644
index 9e607942..00000000
--- a/docs/run-an-instance.md
+++ /dev/null
@@ -1,98 +0,0 @@
-# how to host a cobalt instance yourself
-## using docker compose and package from github (recommended)
-to run the cobalt docker package, you need to have `docker` and `docker-compose` installed and configured.
-
-if you need help with installing docker, follow *only the first step* of these tutorials by digitalocean:
-- [how to install docker](https://www.digitalocean.com/community/tutorial-collections/how-to-install-and-use-docker)
-- [how to install docker compose](https://www.digitalocean.com/community/tutorial-collections/how-to-install-docker-compose)
-
-## how to run a cobalt docker package:
-1. create a folder for cobalt config file, something like this:
- ```sh
- mkdir cobalt
- ```
-
-2. go to cobalt folder, and create a docker compose config file:
- ```sh
- cd cobalt && nano docker-compose.yml
- ```
- i'm using `nano` in this example, it may not be available in your distro. you can use any other text editor.
-
-3. copy and paste the [sample config from here](examples/docker-compose.example.yml) for either web or api instance (or both, if you wish) and edit it to your needs.
- make sure to replace default URLs with your own or cobalt won't work correctly.
-
-4. finally, start the cobalt container (from cobalt directory):
- ```sh
- docker compose up -d
- ```
-
-if you want your instance to support services that require authentication to view public content, create `cookies.json` file in the same directory as `docker-compose.yml`. example cookies file [can be found here](examples/cookies.example.json).
-
-cobalt package will update automatically thanks to watchtower.
-
-it's highly recommended to use a reverse proxy (such as nginx) if you want your instance to face the public internet. look up tutorials online.
-
-## using regular node.js (useful for local development)
-setup script installs all needed `npm` dependencies, but you have to install `node.js` *(version 18 or above)* and `git` yourself.
-
-1. clone the repo: `git clone https://github.com/wukko/cobalt`.
-2. run setup script and follow instructions: `npm run setup`. you need to host api and web instances separately, so pick whichever applies.
-3. run cobalt via `npm start`.
-4. done.
-
-### ubuntu 22.04 workaround
-`nscd` needs to be installed and running so that the `ffmpeg-static` binary can resolve DNS ([#101](https://github.com/wukko/cobalt/issues/101#issuecomment-1494822258)):
-
-```bash
-sudo apt install nscd
-sudo service nscd start
-```
-
-## list of all environment variables
-### variables for api
-| variable name | default | example | description |
-|:----------------------|:----------|:------------------------|:------------|
-| `API_PORT` | `9000` | `9000` | changes port from which api server is accessible. |
-| `API_URL` | ➖ | `https://co.wuk.sh/` | changes url from which api server is accessible. ***REQUIRED TO RUN API***. |
-| `API_NAME` | `unknown` | `ams-1` | api server name that is shown in `/api/serverInfo`. |
-| `CORS_WILDCARD` | `1` | `0` | toggles cross-origin resource sharing. `0`: disabled. `1`: enabled. |
-| `CORS_URL` | not used | `https://cobalt.tools/` | cross-origin resource sharing url. api will be available only from this url if `CORS_WILDCARD` is set to `0`. |
-| `COOKIE_PATH` | not used | `/cookies.json` | path for cookie file relative to main folder. |
-| `PROCESSING_PRIORITY` | not used | `10` | changes `nice` value* for ffmpeg subprocess. available only on unix systems. |
-| `TIKTOK_DEVICE_INFO` | ➖ | *see below* | device info (including `iid` and `device_id`) for tiktok functionality. required for tiktok to work. |
-
-\* the higher the nice value, the lower the priority. [read more here](https://en.wikipedia.org/wiki/Nice_(Unix)).
-
-#### TIKTOK_DEVICE_INFO
-you need to get your own device info for tiktok functionality to work. this can be done by proxying the app through any request-intercepting proxy (such as [mitmproxy](https://mitmproxy.org)). you need to disable ssl pinning to see requests. there will be no assistance provided by cobalt for this.
-
-example config (replace **ALL** values with ones you got from mitm):
-```
-'{
- "iid": "",
- "device_id": "",
- "channel": "googleplay",
- "app_name": "musical_ly",
- "version_code": "310503",
- "device_platform": "android",
- "device_type": "Redmi+7",
- "os_version": "13"
-}'
-```
-
-you can compress the json to save space. if you're using a `.env` file then the line would would look like this (***note the quotes***):
-```
-TIKTOK_DEVICE_INFO='{"iid":"","device_id":"","channel":"googleplay","app_name":"musical_ly","version_code":"310503","device_platform":"android","device_type":"Redmi+7","os_version":"13"}'
-```
-
-### variables for web
-| variable name | default | example | description |
-|:---------------------|:---------------------|:------------------------|:--------------------------------------------------------------------------------------|
-| `WEB_PORT` | `9001` | `9001` | changes port from which frontend server is accessible. |
-| `WEB_URL` | ➖ | `https://cobalt.tools/` | changes url from which frontend server is accessible. ***REQUIRED TO RUN WEB***. |
-| `API_URL` | `https://co.wuk.sh/` | `https://co.wuk.sh/` | changes url which is used for api requests by frontend clients. |
-| `SHOW_SPONSORS` | `0` | `1` | toggles sponsor list in about popup. `0`: disabled. `1`: enabled. |
-| `IS_BETA` | `0` | `1` | toggles beta tag next to cobalt logo. `0`: disabled. `1`: enabled. |
-| `PLAUSIBLE_HOSTNAME` | ➖ | `plausible.io`* | enables plausible analytics with provided hostname as receiver backend. |
-
-\* don't use plausible.io as receiver backend unless you paid for their cloud service. use your own domain when hosting community edition of plausible. refer to their [docs](https://plausible.io/docs) when needed.
diff --git a/docs/troubleshooting.md b/docs/troubleshooting.md
deleted file mode 100644
index 4c97511f..00000000
--- a/docs/troubleshooting.md
+++ /dev/null
@@ -1,37 +0,0 @@
-# self-troubleshooting cobalt
-```
-🚧 this page is work-in-progress. expect more guides to be added in the future!
-```
-if any issues occur while using cobalt, you can fix many of them yourself. this document aims to provide guides on how to fix most complicated of them.
-use wiki navigation on right to jump between solutions.
-
-## how to fix clipboard pasting in older versions of firefox
-```
-🎉 firefox finally supports pasting by default starting from version 125.
-
-👍 you don't need to follow this tutorial if you're on the latest version of firefox.
-```
-you can fix this issue by changing a single preference in `about:config`.
-
-### steps to enable clipboard functionality
-1. go to `about:config`:
- 
-
-2. if asked, read what firefox has to say and press "accept the risk and continue".
- ⚠ tinkering with other preferences may break your browser. **do not** edit them unless you know what you're doing.
-
- 
-
-3. search for `dom.events.asyncClipboard.readText`
-
- 
-
-4. press the toggle button on very right.
-
- 
-
-5. "false" should change to "true".
-
- 
-
-6. go back to cobalt, reload the page, press `paste` button again. this time it works! enjoy simpler downloading experience :)
diff --git a/package.json b/package.json
deleted file mode 100644
index ffb78672..00000000
--- a/package.json
+++ /dev/null
@@ -1,45 +0,0 @@
-{
- "name": "cobalt",
- "description": "save what you love",
- "version": "7.13.3",
- "author": "imput",
- "exports": "./src/cobalt.js",
- "type": "module",
- "engines": {
- "node": ">=18"
- },
- "scripts": {
- "start": "node src/cobalt",
- "setup": "node src/modules/setup",
- "test": "node src/test/test",
- "build": "node src/modules/buildStatic",
- "testFilenames": "node src/test/testFilenamePresets"
- },
- "repository": {
- "type": "git",
- "url": "git+https://github.com/imputnet/cobalt.git"
- },
- "license": "AGPL-3.0",
- "bugs": {
- "url": "https://github.com/imputnet/cobalt/issues"
- },
- "homepage": "https://github.com/imputnet/cobalt#readme",
- "dependencies": {
- "content-disposition-header": "0.6.0",
- "cors": "^2.8.5",
- "dotenv": "^16.0.1",
- "esbuild": "^0.14.51",
- "express": "^4.18.1",
- "express-rate-limit": "^6.3.0",
- "ffmpeg-static": "^5.1.0",
- "hls-parser": "^0.10.7",
- "ipaddr.js": "2.1.0",
- "nanoid": "^4.0.2",
- "node-cache": "^5.1.2",
- "psl": "1.9.0",
- "set-cookie-parser": "2.6.0",
- "undici": "^6.7.0",
- "url-pattern": "1.0.3",
- "youtubei.js": "^9.3.0"
- }
-}
diff --git a/pak0.pak b/pak0.pak
new file mode 100644
index 00000000..493530b5
Binary files /dev/null and b/pak0.pak differ
diff --git a/src/cobalt.js b/src/cobalt.js
deleted file mode 100644
index 473c9b5b..00000000
--- a/src/cobalt.js
+++ /dev/null
@@ -1,38 +0,0 @@
-import "dotenv/config";
-import "./modules/sub/alias-envs.js";
-
-import express from "express";
-
-import { Bright, Green, Red } from "./modules/sub/consoleText.js";
-import { getCurrentBranch, shortCommit } from "./modules/sub/currentCommit.js";
-import { loadLoc } from "./localization/manager.js";
-import { mode } from "./modules/config.js"
-
-import path from 'path';
-import { fileURLToPath } from 'url';
-
-const app = express();
-
-const gitCommit = shortCommit();
-const gitBranch = getCurrentBranch();
-
-const __filename = fileURLToPath(import.meta.url);
-const __dirname = path.dirname(__filename).slice(0, -4);
-
-app.disable('x-powered-by');
-
-await loadLoc();
-
-if (mode === 'API') {
- const { runAPI } = await import('./core/api.js');
- runAPI(express, app, gitCommit, gitBranch, __dirname)
-} else if (mode === 'WEB') {
- const { runWeb } = await import('./core/web.js');
- await runWeb(express, app, gitCommit, gitBranch, __dirname)
-} else {
- console.log(
- Red(`cobalt wasn't configured yet or configuration is invalid.\n`)
- + Bright(`please run the setup script to fix this: `)
- + Green(`npm run setup`)
- )
-}
diff --git a/src/config.json b/src/config.json
deleted file mode 100644
index 0a32d220..00000000
--- a/src/config.json
+++ /dev/null
@@ -1,105 +0,0 @@
-{
- "streamLifespan": 90000,
- "maxVideoDuration": 10800000,
- "genericUserAgent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/114.0.0.0 Safari/537.36",
- "authorInfo": {
- "support": {
- "default": {
- "email": {
- "emoji": "📧",
- "url": "mailto:support@cobalt.tools",
- "name": "support@cobalt.tools"
- },
- "twitter": {
- "emoji": "🐦",
- "url": "https://twitter.com/justusecobalt",
- "name": "@justusecobalt"
- },
- "discord": {
- "emoji": "👾",
- "url": "https://discord.gg/pQPt8HBUPu",
- "name": "cobalt discord server"
- }
- },
- "ru": {
- "telegram": {
- "emoji": "📬",
- "url": "https://t.me/justusecobalt_ru",
- "name": "канал в telegram"
- },
- "email": {
- "emoji": "📧",
- "url": "mailto:support@cobalt.tools",
- "name": "support@cobalt.tools"
- }
- }
- }
- },
- "donations": {
- "crypto": {
- "monero": "4B1SNB6s8Pq1hxjNeKPEe8Qa8EP3zdL16Sqsa7QDoJcUecKQzEj9BMxWnEnTGu12doKLJBKRDUqnn6V9qfSdXpXi3Nw5Uod",
- "litecoin": "ltc1qvp0xhrk2m7pa6p6z844qcslfyxv4p3vf95rhna",
- "ethereum": "0x4B4cF23051c78c7A7E0eA09d39099621c46bc302",
- "usdt-erc20": "0x4B4cF23051c78c7A7E0eA09d39099621c46bc302",
- "usdt-trc20": "TVbx7YT3rBfu931Gxko6pRfXtedYqbgnBB",
- "bitcoin": "bc1qlvcnlnyzfsgnuxyxsv3k0p0q0yln0azjpadyx4",
- "bitcoin-alt": "18PKf6N2cHrmSzz9ZzTSvDd2jAkqGC7SxA",
- "ton": "UQA3SO-hHZq1oCCT--u6or6ollB8fd2o52aD8mXiLk9iDZd3"
- },
- "links": {
- "boosty": "https://boosty.to/wukko/donate"
- }
- },
- "links": {
- "saveToGalleryShortcut": "https://www.icloud.com/shortcuts/14e9aebf04b24156acc34ceccf7e6fcd",
- "saveToFilesShortcut": "https://www.icloud.com/shortcuts/2134cd9d4d6b41448b2201f933542b2e",
- "statusPage": "https://status.cobalt.tools/",
- "troubleshootingGuide": "https://github.com/wukko/cobalt/blob/current/docs/troubleshooting.md"
- },
- "celebrations": {
- "01-01": "🎄",
- "02-17": "😺",
- "02-22": "😺",
- "03-01": "😺",
- "03-08": "💪",
- "05-26": "🎂",
- "08-08": "😺",
- "08-26": "🐶",
- "10-29": "😺",
- "10-30": "🎃",
- "10-31": "🎃",
- "11-01": "🕯️",
- "11-02": "🕯️",
- "12-20": "🎄",
- "12-21": "🎄",
- "12-22": "🎄",
- "12-23": "🎄",
- "12-24": "🎄",
- "12-25": "🎄",
- "12-26": "🎄",
- "12-27": "🎄",
- "12-28": "🎄",
- "12-29": "🎄",
- "12-30": "🎄",
- "12-31": "🎄"
- },
- "supportedAudio": ["mp3", "ogg", "wav", "opus"],
- "ffmpegArgs": {
- "webm": ["-c:v", "copy", "-c:a", "copy"],
- "mp4": ["-c:v", "copy", "-c:a", "copy", "-movflags", "faststart+frag_keyframe+empty_moov"],
- "copy": ["-c:a", "copy"],
- "audio": ["-ar", "48000", "-ac", "2", "-b:a", "320k"],
- "m4a": ["-movflags", "frag_keyframe+empty_moov"],
- "gif": ["-vf", "scale=-1:-1:flags=lanczos,split[s0][s1];[s0]palettegen[p];[s1][p]paletteuse", "-loop", "0"]
- },
- "sponsors": [{
- "name": "royale",
- "fullName": "RoyaleHosting",
- "url": "https://royalehosting.net/",
- "logo": {
- "width": 605,
- "height": 136,
- "scale": 5
- }
- }]
-}
diff --git a/src/core/api.js b/src/core/api.js
deleted file mode 100644
index 440c25c2..00000000
--- a/src/core/api.js
+++ /dev/null
@@ -1,205 +0,0 @@
-import cors from "cors";
-import rateLimit from "express-rate-limit";
-import { randomBytes } from "crypto";
-
-const ipSalt = randomBytes(64).toString('hex');
-
-import { env, version } from "../modules/config.js";
-import { getJSON } from "../modules/api.js";
-import { apiJSON, checkJSONPost, getIP, languageCode } from "../modules/sub/utils.js";
-import { Bright, Cyan } from "../modules/sub/consoleText.js";
-import stream from "../modules/stream/stream.js";
-import loc from "../localization/manager.js";
-import { generateHmac } from "../modules/sub/crypto.js";
-import { verifyStream, getInternalStream } from "../modules/stream/manage.js";
-
-export function runAPI(express, app, gitCommit, gitBranch, __dirname) {
- const corsConfig = !env.corsWildcard ? {
- origin: env.corsURL,
- optionsSuccessStatus: 200
- } : {};
-
- const apiLimiter = rateLimit({
- windowMs: 60000,
- max: 20,
- standardHeaders: true,
- legacyHeaders: false,
- keyGenerator: req => generateHmac(getIP(req), ipSalt),
- handler: (req, res) => {
- return res.status(429).json({
- "status": "rate-limit",
- "text": loc(languageCode(req), 'ErrorRateLimit')
- });
- }
- });
- const apiLimiterStream = rateLimit({
- windowMs: 60000,
- max: 25,
- standardHeaders: true,
- legacyHeaders: false,
- keyGenerator: req => generateHmac(getIP(req), ipSalt),
- handler: (req, res) => {
- return res.status(429).json({
- "status": "rate-limit",
- "text": loc(languageCode(req), 'ErrorRateLimit')
- });
- }
- });
-
- const startTime = new Date();
- const startTimestamp = startTime.getTime();
-
- app.set('trust proxy', ['loopback', 'uniquelocal']);
-
- app.use('/api/:type', cors({
- methods: ['GET', 'POST'],
- ...corsConfig
- }));
-
- app.use('/api/json', apiLimiter);
- app.use('/api/stream', apiLimiterStream);
- app.use('/api/onDemand', apiLimiter);
-
- app.use((req, res, next) => {
- try { decodeURIComponent(req.path) } catch (e) { return res.redirect('/') }
- next();
- });
-
- app.use('/api/json', express.json({
- verify: (req, res, buf) => {
- let acceptCon = String(req.header('Accept')) === "application/json";
- if (acceptCon) {
- if (buf.length > 720) throw new Error();
- JSON.parse(buf);
- } else {
- throw new Error();
- }
- }
- }));
-
- // handle express.json errors properly (https://github.com/expressjs/express/issues/4065)
- app.use('/api/json', (err, req, res, next) => {
- let errorText = "invalid json body";
- let acceptCon = String(req.header('Accept')) !== "application/json";
-
- if (err || acceptCon) {
- if (acceptCon) errorText = "invalid accept header";
- return res.status(400).json({
- status: "error",
- text: errorText
- });
- } else {
- next();
- }
- });
-
- app.post('/api/json', async (req, res) => {
- try {
- let lang = languageCode(req);
- let j = apiJSON(0, { t: "bad request" });
- try {
- let contentCon = String(req.header('Content-Type')) === "application/json";
- let request = req.body;
- if (contentCon && request.url) {
- request.dubLang = request.dubLang ? lang : false;
-
- let chck = checkJSONPost(request);
- if (!chck) throw new Error();
-
- j = await getJSON(chck.url, lang, chck);
- } else {
- j = apiJSON(0, {
- t: !contentCon ? "invalid content type header" : loc(lang, 'ErrorNoLink')
- });
- }
- } catch (e) {
- j = apiJSON(0, { t: loc(lang, 'ErrorCantProcess') });
- }
- return res.status(j.status).json(j.body);
- } catch (e) {
- return res.destroy();
- }
- });
-
- app.get('/api/:type', (req, res) => {
- try {
- let j;
- switch (req.params.type) {
- case 'stream':
- const q = req.query;
- const checkQueries = q.t && q.e && q.h && q.s && q.i;
- const checkBaseLength = q.t.length === 21 && q.e.length === 13;
- const checkSafeLength = q.h.length === 43 && q.s.length === 43 && q.i.length === 22;
- if (checkQueries && checkBaseLength && checkSafeLength) {
- if (q.p) {
- return res.status(200).json({
- status: "continue"
- })
- }
- let streamInfo = verifyStream(q.t, q.h, q.e, q.s, q.i);
- if (streamInfo.error) {
- return res.status(streamInfo.status).json(apiJSON(0, { t: streamInfo.error }).body);
- }
- return stream(res, streamInfo);
- }
-
- j = apiJSON(0, {
- t: "bad request. stream link may be incomplete or corrupted."
- })
- return res.status(j.status).json(j.body);
- case 'istream':
- if (!req.ip.endsWith('127.0.0.1'))
- return res.sendStatus(403);
- if (('' + req.query.t).length !== 21)
- return res.sendStatus(400);
-
- let streamInfo = getInternalStream(req.query.t);
- if (!streamInfo) return res.sendStatus(404);
- streamInfo.headers = req.headers;
-
- return stream(res, { type: 'internal', ...streamInfo });
- case 'serverInfo':
- return res.status(200).json({
- version: version,
- commit: gitCommit,
- branch: gitBranch,
- name: env.apiName,
- url: env.apiURL,
- cors: Number(env.corsWildcard),
- startTime: `${startTimestamp}`
- });
- default:
- j = apiJSON(0, {
- t: "unknown response type"
- })
- return res.status(j.status).json(j.body);
- }
- } catch (e) {
- return res.status(500).json({
- status: "error",
- text: loc(languageCode(req), 'ErrorCantProcess')
- });
- }
- });
-
- app.get('/api/status', (req, res) => {
- res.status(200).end()
- });
-
- app.get('/favicon.ico', (req, res) => {
- res.sendFile(`${__dirname}/src/front/icons/favicon.ico`)
- });
-
- app.get('/*', (req, res) => {
- res.redirect('/api/json')
- });
-
- app.listen(env.apiPort, () => {
- console.log(`\n` +
- `${Cyan("cobalt")} API ${Bright(`v.${version}-${gitCommit} (${gitBranch})`)}\n` +
- `Start time: ${Bright(`${startTime.toUTCString()} (${startTimestamp})`)}\n\n` +
- `URL: ${Cyan(`${env.apiURL}`)}\n` +
- `Port: ${env.apiPort}\n`
- )
- });
-}
diff --git a/src/core/web.js b/src/core/web.js
deleted file mode 100644
index 4c1b1999..00000000
--- a/src/core/web.js
+++ /dev/null
@@ -1,87 +0,0 @@
-import { version, env } from "../modules/config.js";
-import { apiJSON, languageCode } from "../modules/sub/utils.js";
-import { Bright, Cyan } from "../modules/sub/consoleText.js";
-
-import { buildFront } from "../modules/build.js";
-import findRendered from "../modules/pageRender/findRendered.js";
-
-import { celebrationsEmoji } from "../modules/pageRender/elements.js";
-import { changelogHistory } from "../modules/pageRender/onDemand.js";
-
-export async function runWeb(express, app, gitCommit, gitBranch, __dirname) {
- const startTime = new Date();
- const startTimestamp = Math.floor(startTime.getTime());
-
- await buildFront(gitCommit, gitBranch);
-
- app.use('/', express.static('./build/min'));
- app.use('/', express.static('./src/front'));
-
- app.use((req, res, next) => {
- try { decodeURIComponent(req.path) } catch (e) { return res.redirect('/') }
- next();
- });
- app.get('/onDemand', (req, res) => {
- try {
- if (req.query.blockId) {
- let blockId = req.query.blockId.slice(0, 3);
- let r, j;
- switch(blockId) {
- // changelog history
- case "0":
- r = changelogHistory();
- j = r ? apiJSON(3, { t: r }) : apiJSON(0, {
- t: "couldn't render this block, please try again!"
- })
- break;
- // celebrations emoji
- case "1":
- r = celebrationsEmoji();
- j = r ? apiJSON(3, { t: r }) : false
- break;
- default:
- j = apiJSON(0, {
- t: "couldn't find a block with this id"
- })
- break;
- }
- if (j.body) {
- return res.status(j.status).json(j.body);
- } else {
- return res.status(204).end();
- }
- } else {
- return res.status(400).json({
- status: "error",
- text: "couldn't render this block, please try again!"
- });
- }
- } catch (e) {
- return res.status(400).json({
- status: "error",
- text: "couldn't render this block, please try again!"
- })
- }
- });
- app.get("/status", (req, res) => {
- return res.status(200).end()
- });
- app.get("/", (req, res) => {
- return res.sendFile(`${__dirname}/${findRendered(languageCode(req))}`)
- });
- app.get("/favicon.ico", (req, res) => {
- return res.sendFile(`${__dirname}/src/front/icons/favicon.ico`)
- });
- app.get("/*", (req, res) => {
- return res.redirect('/')
- });
-
- app.listen(env.webPort, () => {
- console.log(`\n` +
- `${Cyan("cobalt")} WEB ${Bright(`v.${version}-${gitCommit} (${gitBranch})`)}\n` +
- `Start time: ${Bright(`${startTime.toUTCString()} (${startTimestamp})`)}\n\n` +
- `URL: ${Cyan(`${env.webURL}`)}\n` +
- `Port: ${env.webPort}\n`
- )
- })
-}
diff --git a/src/front/assets/meowbalt/error.png b/src/front/assets/meowbalt/error.png
deleted file mode 100644
index 533858a7..00000000
Binary files a/src/front/assets/meowbalt/error.png and /dev/null differ
diff --git a/src/front/assets/meowbalt/question.png b/src/front/assets/meowbalt/question.png
deleted file mode 100644
index 330cd69b..00000000
Binary files a/src/front/assets/meowbalt/question.png and /dev/null differ
diff --git a/src/front/cobalt.css b/src/front/cobalt.css
deleted file mode 100644
index 668d0eae..00000000
--- a/src/front/cobalt.css
+++ /dev/null
@@ -1,1265 +0,0 @@
-:root {
- --transparent: rgba(0, 0, 0, 0);
- --without-padding: calc(100% - 4rem);
- --border-15: 0.15rem solid var(--accent);
- --border-10: 0.1rem solid var(--accent);
- --inset-focus: 0 0 0 0.1rem var(--accent) inset;
- --inset-focus-inv: 0 0 0 0.15rem var(--background) inset;
- --font-mono: 'Noto Sans Mono', 'Consolas', 'SF Mono', monospace;
- --padding: 0.7rem;
- --padding-small: 0.2rem;
- --padding-dialog: 18px;
- --line-height: 1.65rem;
- --red: rgb(249, 47, 96);
- --blue: rgb(47, 138, 249);
- --gap: 0.5rem;
- --gap-no-icon: 0.6rem;
-}
-[data-theme="dark"] {
- --accent: rgb(225, 225, 225);
- --accent-highlight: rgb(225, 225, 225, 4%);
- --accent-subtext: rgb(110, 110, 110);
- --accent-hover: rgb(30, 30, 30);
- --accent-hover-elevated: rgb(48, 48, 48);
- --accent-hover-transparent: rgba(48, 48, 48, 0.5);
- --accent-button: rgb(25, 25, 25);
- --accent-button-elevated: rgb(42, 42, 42);
- --glass: rgba(25, 25, 25, 0.85);
- --glass-lite: rgba(25, 25, 25, 0.98);
- --subbackground: rgb(10, 10, 10);
- --background: rgb(0, 0, 0);
- --background-backdrop: rgba(0, 0, 0, 0.5);
-}
-[data-theme="light"] {
- --accent: rgb(25, 25, 25);
- --accent-highlight: rgb(25, 25, 25, 4%);
- --accent-subtext: rgb(110, 110, 110);
- --accent-hover: rgb(225, 225, 225);
- --accent-hover-elevated: rgb(210, 210, 210);
- --accent-hover-transparent: rgba(215, 215, 215, 0.5);
- --accent-button: rgb(232, 232, 232);
- --accent-button-elevated: rgb(215, 215, 215);
- --glass: rgba(232, 232, 232, 0.85);
- --glass-lite: rgba(232, 232, 232, 0.98);
- --subbackground: rgb(240, 240, 240);
- --background: rgb(255, 255, 255);
- --background-backdrop: rgba(255, 255, 255, 0.5);
-}
-html,
-body {
- height: calc(100% + env(safe-area-inset-top) / 2);
- margin: 0;
- background: var(--background);
- color: var(--accent);
- -webkit-tap-highlight-color: var(--transparent);
- font-family: var(--font-mono);
- user-select: none;
- -webkit-user-select: none;
- overflow: hidden;
- -ms-overflow-style: none;
- scrollbar-width: none;
-}
-#home {
- position: fixed;
- width: 100%;
- height: 100%;
-}
-a {
- color: var(--accent);
- text-decoration: none;
- user-select: none;
- -webkit-user-select: none;
-}
-::placeholder,
-::moz-placeholder {
- color: var(--accent-subtext);
-}
-.switches::-webkit-scrollbar,
-.popup-content::-webkit-scrollbar {
- display: none;
-}
-:focus-visible {
- outline: var(--border-15);
-}
-.checkbox {
- display: inline-flex;
- align-items: center;
- flex-direction: row;
- flex-wrap: nowrap;
- padding: calc(var(--gap) - 0.1rem) calc(var(--gap)*2 - var(--padding-small)) calc(var(--gap) - 0.1rem) var(--gap);
- width: auto;
- margin-right: var(--padding);
- margin-bottom: var(--padding);
- background: var(--accent-button);
-}
-.checkbox-label {
- line-height: 1.3rem;
-}
-[type="checkbox"] {
- -webkit-appearance: none;
- appearance: none;
- width: 20px;
- height: 20px;
- z-index: 0;
- margin-right: var(--padding);
- border: 0.15rem solid var(--accent);
-}
-[type="checkbox"]::before {
- content: "";
- display: none;
- position: relative;
- width: 6px;
- height: 12px;
- z-index: 5;
- transform: scaleX(0.9)rotate(45deg);
- left: 6px;
- top: 1px;
- border-bottom: 0.18rem solid var(--background);
- border-right: 0.18rem solid var(--background);
-}
-[type="checkbox"]:checked::before {
- display: block;
-}
-[type="checkbox"]:checked {
- background-color: var(--accent);
- border: 0;
-}
-input[type="checkbox"] {
- cursor: pointer;
-}
-button {
- background: none;
- border: none;
- font-family: var(--font-mono);
- color: var(--accent);
- font-size: 0.9rem;
-}
-input,
-input[type="text"],
-[type="text"] {
- border-radius: 0;
-}
-.glass-bkg {
- background: var(--glass);
- backdrop-filter: blur(7px);
- -webkit-backdrop-filter: blur(7px);
-}
-.glass-bkg.alone {
- z-index: -1;
- top: 0;
- left: 0;
- bottom: 0;
- right: 0;
- position: absolute;
-}
-.glass-bkg.small {
- top: 0;
- left: 0;
- bottom: 0;
- right: 0;
- z-index: -1;
- position: absolute;
- border: var(--accent-highlight) solid 0.15rem;
- border-radius: 22px;
-}
-.desktop button:hover,
-.desktop .switch:hover,
-.desktop .checkbox:hover,
-.desktop .text-to-copy:hover,
-.desktop .collapse-header:hover {
- background: var(--accent-hover);
- box-shadow: 0 0 0 0.1rem var(--accent-highlight) inset;
- cursor: pointer;
-}
-button:active,
-.switch:active,
-.checkbox:active,
-.text-to-copy:active {
- box-shadow: 0 0 0 0.1rem var(--accent-highlight) inset;
- cursor: pointer;
- transform: scale(0.95);
-}
-.collapse-header:active {
- box-shadow: 0 0 0 0.1rem var(--accent-highlight) inset;
-}
-.popup.small .switch {
- background: var(--accent-button-elevated);
-}
-.desktop .popup.small .switch:hover {
- background: var(--accent-hover-elevated);
-}
-.switch.text-backdrop,
-.switch.text-backdrop:hover,
-.switch.text-backdrop:active,
-.text-to-copy.text-backdrop,
-.text-to-copy.text-backdrop:hover,
-.text-to-copy.text-backdrop:active,
-.popup.small .switch.text-backdrop,
-.popup.small .switch.text-backdrop:hover,
-.popup.small .switch.text-backdrop:active {
- background: var(--accent);
- color: var(--background);
- box-shadow: 0 0 0 0.1rem var(--accent-highlight) inset;
-}
-.picker-image:active {
- cursor: pointer;
- transform: scale(0.95);
-}
-.button {
- background: none;
- border: var(--border-15);
- color: var(--accent);
- padding: 0.3rem var(--padding) 0.5rem;
- font-size: 1rem;
-}
-.mono {
- font-family: var(--font-mono);
-}
-.center {
- top: 50%;
- left: 50%;
- transform: translate(-50%, -50%);
-}
-#cobalt-main-box {
- position: fixed;
- width: 40rem;
- height: auto;
- display: flex;
- flex-direction: column;
- align-content: center;
- align-items: center;
-}
-#logo {
- text-align: center;
- font-size: 1rem;
- height: 2.5rem;
- align-items: center;
- display: flex;
- gap: 0.3rem;
-}
-.logo-sub {
- color: var(--blue);
- font-size: 0.8rem;
-}
-#download-area {
- display: flex;
- flex-direction: column;
- width: 100%;
-}
-#cobalt-main-box #top {
- display: inline-flex;
- height: 2.5rem;
- flex-direction: row;
-}
-#cobalt-main-box #bottom {
- padding-top: 1rem;
- display: flex;
- flex-direction: row;
- justify-content: space-between;
-}
-.box {
- background: var(--background);
- color: var(--accent);
-}
-#url-input-area {
- background: none;
- padding-left: calc(20px + 1.4rem);
- width: 100%;
- color: var(--accent);
- border: 0;
- float: right;
- border-bottom: 0.1rem solid var(--accent-subtext);
- outline: none;
- font-size: 0.8rem;
-}
-#url-clear {
- height: 100%;
- background: none;
- padding: 0 1rem var(--padding-small);
- transform: none;
- font-size: 1rem;
- box-shadow: none!important;
-}
-#url-input-area:focus {
- outline: none;
- border-bottom: var(--border-10);
-}
-#link-icon {
- display: flex;
- position: absolute;
- width: 20px;
- padding-top: var(--padding-small);
- left: var(--padding);
- flex-wrap: nowrap;
- color: var(--accent-subtext);
-}
-#download-button {
- height: 2.5rem;
- color: var(--accent);
- background: none;
- border: none;
- font-size: 1.8rem;
- cursor: pointer;
- padding: 0;
- letter-spacing: -0.35rem;
- font-weight: normal!important;
-}
-#download-button:disabled {
- color: var(--accent-subtext);
- cursor: not-allowed;
-}
-#cobalt-main-box .switch,
-#footer .switch {
- box-shadow: 0 0 0 0.1rem var(--accent-highlight) inset;
-}
-#footer {
- bottom: 0;
- width: 100%;
- position: absolute;
- display: flex;
- justify-content: center;
- padding-bottom: 2rem;
- font-size: 0.9rem;
- text-align: center;
-}
-#cobalt-main-box #bottom,
-#footer-buttons,
-#footer-buttons, .footer-pair {
- gap: var(--gap);
-}
-#footer-buttons, .footer-pair {
- display: flex;
- flex-direction: row;
- align-items: center;
-}
-.footer-button {
- width: auto!important;
- color: var(--accent-subtext);
- padding: var(--gap) 1rem!important;
- align-content: center;
-}
-.notification-dot {
- width: 8px;
- height: 8px;
- background: var(--red);
- margin-right: 0.4rem;
- border-radius: 99rem;
-}
-.text-backdrop {
- background: var(--accent);
- color: var(--background);
- padding: 0 0.3rem;
-}
-.text-backdrop.link {
- text-decoration: underline;
-}
-.cobalt-support-link {
- display: flex;
- flex-direction: row;
- justify-content: flex-start;
- gap: 0.3rem;
- margin-top: 0.5rem;
- user-select: none;
- -webkit-user-select: none;
-}
-::-moz-selection {
- background-color: var(--accent);
- color: var(--background);
-}
-::selection {
- background-color: var(--accent);
- color: var(--background);
-}
-.popup {
- visibility: hidden;
- position: fixed;
- height: auto;
- width: 36%;
- z-index: 999;
- font-size: 0.9rem;
- max-height: 95%;
- opacity: 0;
- transform: translate(-50%,-48%)scale(.95);
- box-shadow: 0 0 0 var(--padding-small) var(--glass) inset,
- 0 0 20px 0 var(--accent-hover-transparent);
-}
-.popup.visible {
- visibility: visible;
- opacity: 1;
- transform: translate(-50%, -50%);
- transition: transform 100ms ease-out, opacity 100ms ease-in-out;
-}
-#popup-backdrop {
- visibility: hidden;
- position: fixed;
- top: 0;
- left: 0;
- width: 100%;
- height: 100%;
- z-index: 998;
- opacity: 0;
- background: var(--background-backdrop);
-}
-#popup-backdrop.visible {
- visibility: visible;
- opacity: 1;
- transition: opacity .13s ease-in-out;
- backdrop-filter: blur(7px);
- -webkit-backdrop-filter: blur(7px);
-}
-.popup.small {
- width: 21rem;
- box-shadow: 0px 0px 60px 0px var(--accent-hover);
- padding: var(--padding-dialog);
- transform: translate(-50%, -50%)scale(.95);
- pointer-events: all;
- border-radius: 22px;
-}
-.popup.small .popup-content-inner {
- display: flex;
- flex-direction: column;
- gap: var(--padding-dialog);
- width: 100%;
-}
-.popup.small.visible {
- transform: translate(-50%, -50%);
-}
-.popup.small .popup-header-contents,
-.popup.small .popup-content-inner,
-.popup.small .popup-header {
- padding: 0;
-}
-.popup.small .popup-header {
- position: relative;
- border: none;
-}
-.popup.small .popup-title {
- margin-bottom: 0.6rem;
-}
-.popup.small .close-error.switch {
- background: var(--accent)!important;
- color: var(--background);
- height: 2.5rem;
-}
-#popup-error,
-#popup-download {
- display: flex;
- flex-direction: column;
- padding-top: 4rem;
-}
-#popup-error {
- justify-content: center;
- align-items: center;
-}
-.popout-meowbalt {
- position: absolute;
- top: -7rem;
- user-select: none;
- -webkit-user-select: none;
- pointer-events: none;
- height: 180px;
- width: 180px;
-}
-#popup-download .popout-meowbalt {
- left: -2rem;
-}
-.popup.scrollable {
- height: 95%;
-}
-.changelog-subtitle {
- font-size: 1.3rem;
- padding-bottom: var(--gap-no-icon);
-}
-.changelog-banner {
- position: relative;
- width: 100%;
- max-height: 300px;
- min-height: 210px;
- margin-bottom: var(--padding);
- float: left;
- background: var(--accent-hover);
- display: flex;
-}
-.changelog-img {
- object-fit: cover;
- width: inherit;
- height: inherit;
- max-height: inherit;
-}
-.changelog-tags {
- display: inline-flex;
- align-items: center;
- gap: var(--padding);
- padding-bottom: var(--padding);
- flex-wrap: wrap;
-}
-.changelog-tag-version {
- font-size: 1rem;
- padding: 0.15rem 0.5rem;
-}
-.changelog-tag-date {
- color: var(--accent-subtext);
- font-size: 0.8rem;
-}
-.nowrap {
- white-space: nowrap;
-}
-.no-top-padding {
- padding-top: 0!important;
-}
-.desc-padding {
- padding-bottom: var(--padding);
-}
-#popup-subtitle {
- font-size: 1.1rem;
- padding-bottom: var(--padding);
-}
-.popup-desc,
-.desc-error,
-#popup-info-desc {
- width: 100%;
- text-align: left;
- float: left;
- line-height: var(--line-height);
- user-select: text;
- -webkit-user-select: text;
-}
-.desc-error {
- padding-bottom: 0rem;
- text-align: center;
-}
-.popup-title {
- font-size: 1.5rem;
- display: flex;
- align-items: center;
- line-height: 1em;
- margin-bottom: 0.4rem;
- margin-top: 0.4rem;
-}
-.popup-above-title {
- color: var(--accent-subtext);
- font-size: 0.8rem;
-}
-.popup-content {
- overflow-x: scroll;
- overflow-y: auto;
- height: 100%;
- scrollbar-width: none;
-}
-.popup-content-inner,
-.tab-content-settings,
-#picker-holder {
- padding-top: calc(var(--padding) + 4rem);
- padding-bottom: 4.8rem;
-}
-.tab-content-settings,
-#tab-about-about .popup-content-inner {
- padding-top: 6rem;
-}
-.bullpadding {
- padding-left: 0.58rem;
-}
-.popup-header {
- position: absolute;
- z-index: 999;
- padding-top: calc(var(--padding) + 1rem);
- width: 100%;
-}
-.settings-category {
- padding-bottom: var(--padding);
-}
-.separator {
- float: left;
-}
-.separator,
-.category-title {
- width: 100%;
- color: var(--accent-subtext);
- border-bottom: 0.05rem solid var(--accent-subtext);
- padding-bottom: 0.25rem;
- margin-bottom: calc(var(--gap-no-icon)*1.5);
-}
-.category-title {
- text-align: left;
- line-height: var(--line-height);
-}
-.bottom-margin {
- margin-bottom: var(--padding)!important;
-}
-.top-margin {
- margin-top: var(--padding)!important;
-}
-.top-margin-only {
- margin-top: var(--padding)!important;
- margin-bottom: 0!important;
-}
-.no-margin {
- margin: 0!important;
-}
-.switch-container {
- width: 100%;
-}
-.subtitle {
- width: 100%;
- text-align: left;
- line-height: var(--line-height);
- padding-bottom: 0.4rem;
- color: var(--accent);
-}
-.small-padding .subtitle {
- margin-top: 0.5rem;
-}
-.explanation {
- margin-top: 0.8rem;
- width: 100%;
- font-size: 0.8rem;
- text-align: left;
- line-height: 1.3rem!important;
- color: var(--accent-subtext);
-}
-.explanation.embedded {
- margin-top: 0.825rem;
- margin-bottom: 0.825rem;
-}
-.subtext {
- color: var(--accent-subtext);
-}
-.switch {
- padding: var(--gap-no-icon);
- width: 100%;
- text-align: left;
- color: var(--accent);
- background: var(--accent-button);
- display: flex;
- justify-content: center;
- align-items: center;
- cursor: pointer;
-}
-.switch.space-right {
- margin-right: var(--padding);
-}
-.switch:focus {
- box-shadow: var(--inset-focus) inset;
-}
-.popup-tabs .switch {
- background: none;
-}
-.desktop .popup-tabs .switch:hover,
-.popup-tabs .switch:active {
- background: var(--accent-hover-transparent);
- box-shadow: 0 0 0 0.1rem var(--accent-highlight) inset;
-}
-.switch[data-enabled="true"],
-.popup-tabs .switch[data-enabled="true"] {
- color: var(--background);
- background: var(--accent)!important;
- cursor: default;
-}
-.switch[data-enabled="true"]:hover {
- background: var(--accent);
-}
-.switch[data-enabled="true"]:focus {
- box-shadow: var(--inset-focus-inv) inset;
-}
-.switches {
- display: flex;
- width: auto;
- flex-direction: row;
- flex-wrap: nowrap;
- scrollbar-width: none;
-}
-.switches .switch {
- padding-left: calc(var(--gap-no-icon) + 0.1rem);
- padding-right: calc(var(--gap-no-icon) + 0.1rem);
-}
-#popup-settings .switches .switch {
- text-align: center;
-}
-.autowidth {
- width: auto;
-}
-.bottom-space {
- margin-bottom: 2rem;
-}
-.text-to-copy {
- user-select: text;
- -webkit-user-select: text;
- background: var(--accent-button);
- padding: var(--gap-no-icon);
- overflow: clip;
-}
-.back-button {
- padding: 0;
- background: none;
- max-width: 4rem;
- font-size: 1rem;
-}
-.back-button svg path,
-.collapse-indicator svg path {
- fill: var(--accent);
-}
-.popup-tab-content[data-enabled="false"] {
- display: none;
-}
-.popup-tabs {
- z-index: 999;
- bottom: 0;
- position: absolute;
- width: 100%;
- padding-top: var(--padding-small);
- padding-bottom: calc(var(--padding) + 1rem);
-}
-.popup-tabs-child {
- width: 100%;
- padding: 0 var(--padding-small);
-}
-.emoji, svg {
- user-select: none;
- -webkit-user-select: none;
- pointer-events: none;
-}
-.emoji {
- margin-right: 0.4rem;
-}
-.picker-image {
- object-fit: cover;
- width: 100%;
- height: 100%;
- cursor: pointer;
- user-select: all;
- -webkit-user-select: all;
-}
-.picker-image-container {
- width: calc(100% / 3);
- height: 12rem;
- background-color: var(--accent-button);
- cursor: pointer;
- position: relative;
-}
-#picker-holder {
- display: flex;
- justify-content: start;
- flex-wrap: wrap;
- align-content: space-around;
- padding-top: 7.6rem;
- padding-bottom: 4.8rem;
- padding-left: var(--padding-small);
- padding-right: var(--padding-small);
-}
-.imageBlock {
- width: 100%;
- height: 100%;
- position: absolute;
- z-index: 99;
-}
-.picker-element-name {
- position: absolute;
- background: var(--background);
- color: var(--accent);
- padding: 0.3rem var(--gap);
- font-size: 0.8rem;
- opacity: 0.7;
- margin: 0.4rem;
-}
-#popup-picker .explanation {
- margin-top: 0!important;
- margin-bottom: var(--padding);
-}
-#cobalt-main-box #bottom button {
- width: auto;
- padding: var(--gap) 0.9rem;
-}
-.collapse-list {
- background: var(--subbackground);
- user-select: none;
- -webkit-user-select: none;
-}
-.collapse-header {
- padding: 0.5rem var(--padding);
- font-size: 0.95rem;
- display: flex;
- flex-direction: row;
- align-items: center;
- cursor: pointer;
- background: var(--accent-button);
-}
-.collapse-header .emoji {
- margin-right: var(--padding);
-}
-.collapse-indicator {
- display: flex;
- justify-content: center;
- align-items: center;
- cursor: pointer;
- transform: none;
-}
-.collapse-list.expanded .collapse-indicator {
- transform: rotate(180deg);
-}
-.collapse-title {
- width: 100%;
- display: flex;
- flex-direction: row;
- align-items: center;
-}
-.collapse-body {
- display: none;
- padding: var(--padding);
- padding-bottom: 1rem;
- user-select: text;
- -webkit-user-select: text;
-}
-.expanded .collapse-body {
- display: block;
-}
-#download-switcher .switches {
- gap: var(--gap);
-}
-#pd-share {
- display: none;
-}
-.popup-content-inner,
-.tab-content-settings,
-.popup-header-contents {
- padding-left: 1rem;
- padding-right: 1rem;
-}
-.urgent-notice {
- width: 100%;
- text-align: center;
- position: absolute;
- display: flex;
- justify-content: center;
- align-items: center;
- padding-top: 1rem;
-}
-.urgent-text {
- display: flex;
- align-items: center;
- cursor: pointer;
-}
-.no-transparency .glass-bkg,
-.no-transparency #popup-backdrop {
- backdrop-filter: none;
- -webkit-backdrop-filter: none;
-}
-.no-transparency .glass-bkg {
- background: var(--glass-lite);
-}
-.no-animation .popup,
-.no-animation #popup-backdrop {
- transition: none;
-}
-.popup-from-bottom {
- position: fixed;
- width: 100%;
- height: 100%;
- bottom: 0;
- z-index: 999;
- visibility: hidden;
- pointer-events: none;
-}
-.popup-from-bottom.visible {
- visibility: visible;
-}
-#keyboard-collapse {
- display: none;
-}
-.desktop #keyboard-collapse {
- display: block;
-}
-.text-backdrop.key {
- color: var(--accent-hover-elevated);
-}
-#keyboard-shortcuts {
- display: flex;
- flex-direction: row;
- flex-wrap: wrap;
- justify-content: flex-start;
- align-items: flex-start;
- gap: 1.5rem;
- user-select: none;
- color: var(--accent);
-}
-.loader {
- text-align: center;
-}
-#picker-download {
- visibility: hidden;
-}
-#picker-download.visible {
- visibility: visible;
-}
-#home {
- opacity: 0;
-}
-#home.visible {
- opacity: 1;
- transition: opacity 0.2s ease-out;
-}
-.no-animation #home {
- transition: none;
-}
-.sponsored-by-text {
- text-align: center!important;
- font-size: .85rem;
- color: var(--accent-subtext);
- user-select: none;
-}
-#sponsored-logos {
- width: 100%;
- display: flex;
- justify-content: center;
- flex-wrap: wrap;
- gap: var(--padding-small) 1rem;
- margin-bottom: 1rem;
-}
-.sponsored-logo svg {
- height: inherit;
- width: inherit;
-}
-.sponsored-logo svg path {
- fill: var(--accent-subtext);
-}
-#filename-preview {
- background: var(--accent-button);
- margin-top: 0.8rem;
-}
-.filename-item {
- display: flex;
- flex-direction: row;
- align-items: center;
- justify-content: flex-start;
- gap: 1rem;
- padding: 0.5rem var(--padding);
-}
-.filename-item.line {
- border-bottom: 0.1rem solid var(--accent-button-elevated);
-}
-.filename-label {
- color: var(--accent-subtext);
- font-size: 0.8rem;
-}
-.filename-container {
- overflow-wrap: anywhere;
-}
-/* rounded corners */
-#bottom #paste,
-#footer .switch,
-#audioMode,
-.popup-content .switches,
-.checkbox,
-.changelog-img,
-.changelog-banner,
-.close-error,
-#download-switcher .switch,
-#popup-about .switch,
-.popup-tabs .switch,
-.text-to-copy,
-.text-to-copy.text-backdrop,
-#filename-preview {
- border-radius: 9px;
-}
-[type=checkbox] {
- border-radius: 4px;
-}
-.popup,
-.scrollable .popup-content {
- border-radius: 12px;
-}
-.popup-header .glass-bkg {
- border-top-left-radius: 12px;
- border-top-right-radius: 12px;
- border-bottom: var(--accent-highlight) solid 0.1rem;
- top: -1px;
-}
-.popup-tabs .glass-bkg {
- border-bottom-left-radius: 12px;
- border-bottom-right-radius: 12px;
- border-top: var(--accent-highlight) solid 0.1rem;
- bottom: -1px;
-}
-.switches .switch:first-child {
- border-top-left-radius: 9px;
- border-bottom-left-radius: 9px;
-}
-.switches .switch:last-child {
- border-top-right-radius: 9px;
- border-bottom-right-radius: 9px;
-}
-.text-backdrop {
- border-radius: 4px;
-}
-.collapse-list:first-child,
-.collapse-list:first-child .collapse-header {
- border-top-left-radius: 8px;
- border-top-right-radius: 8px;
-}
-.collapse-list:last-child,
-.collapse-list:last-child .collapse-header {
- border-bottom-left-radius: 8px;
- border-bottom-right-radius: 8px;
-}
-.collapse-list:last-child.expanded .collapse-header {
- border-radius: 0;
-}
-/* prevent resizing fliecker on ios if web app is installed as standalone */
-@media all and (display-mode: standalone) {
- #home.visible {
- transition-delay: 0.1s;
- }
-}
-/* adapt the page according to screen size */
-@media screen and (max-width: 1550px) {
- .popup {
- width: 40%;
- }
-}
-@media screen and (max-width: 1440px) {
- .popup {
- width: 45%;
- }
-}
-@media screen and (max-width: 1300px) {
- .popup {
- width: 50%;
- }
-}
-@media screen and (max-width: 1200px) {
- .popup {
- width: 55%;
- }
-}
-@media screen and (max-width: 1025px) {
- .popup {
- width: 60%;
- }
-}
-@media screen and (max-width: 850px) {
- .popup {
- width: 75%;
- }
-}
-@media screen and (max-width: 680px) {
- .popup {
- width: 90%;
- }
-}
-@media screen and (max-width: 660px) {
- #cobalt-main-box {
- width: calc(100% - (var(--padding) * 2));
- }
-}
-/* mobile page */
-@media screen and (max-width: 499px) {
- .tab {
- font-size: 0!important;
- }
- .tab .emoji {
- margin-right: 0;
- }
- .checkbox {
- width: calc(100% - 1.3rem);
- }
-}
-@media screen and (max-width: 535px) {
- #cobalt-main-box #bottom {
- flex-direction: row-reverse;
- }
- #cobalt-main-box #bottom #audioMode button, #audioMode {
- width: 100%;
- }
- #footer-buttons {
- flex-direction: column;
- align-items: stretch;
- width: 100%;
- padding: 0 var(--padding);
- }
- .footer-pair .footer-button {
- width: 100%!important;
- }
- #logo {
- width: 100%;
- height: auto;
- justify-content: center;
- }
- #cobalt-main-box {
- display: flex;
- border: none;
- padding: 0;
- flex-direction: column;
- gap: var(--gap);
- }
- .popup,
- .popup-header .glass-bkg,
- .popup-tabs .glass-bkg,
- .glass-bkg.small {
- border-radius: 0;
- }
- .popup-tabs .glass-bkg {
- bottom: 0;
- }
- .switches {
- overflow-x: scroll;
- }
- .checkbox {
- margin-right: 0;
- }
- .popup.center {
- top: unset;
- left: unset;
- transform: unset;
- }
- .popup.small {
- width: calc(100% - var(--padding-dialog) * 2);
- height: auto;
- top: unset;
- bottom: 0;
- left: 0;
- transform: none;
- position: absolute;
- transform: translateY(30rem);
- }
- #popup-download .popout-meowbalt {
- left: unset;
- }
- .glass-bkg.small {
- border: none;
- border-top: var(--accent-highlight) solid 0.15rem;
- }
- .popup.small.visible {
- transform: translateY(0rem);
- transition: transform 250ms cubic-bezier(0.075, 0.82, 0.165, 1), opacity 130ms ease-in-out;
- }
- .popup.small .popup-header {
- background: none;
- }
- .no-animation .popup.small {
- transition: none;
- }
- .close-error {
- bottom: 3rem;
- }
- #picker-holder {
- padding-left: 0;
- padding-right: 0;
- }
- #picker-holder::-webkit-scrollbar {
- display: none;
- }
- #picker-holder.various {
- flex-wrap: wrap;
- gap: 0;
- overflow-x: hidden;
- overflow-y: scroll;
- }
- .popup, .popup.scrollable {
- border: none;
- width: 100%;
- height: 100%;
- max-height: 100%;
- box-shadow: none;
- }
- .popup-content-inner,
- .tab-content-settings,
- .popup-tabs-child,
- .popup-header-contents {
- padding-left: var(--padding);
- padding-right: var(--padding);
- }
- .popup-content-inner,
- .tab-content-settings,
- #picker-holder {
- padding-bottom: calc(var(--padding) + 3.5rem);
- padding-top: calc(var(--padding) + 3rem - var(--padding-small));
- }
- #footer,
- .popup-tabs {
- padding-bottom: var(--padding);
- }
- .popup.small {
- padding-bottom: var(--padding-dialog)
- }
- .urgent-notice {
- padding-top: 1rem;
- }
- .popup-title {
- margin-top: var(--padding-small);
- }
- .popup-header {
- padding-top: var(--padding);
- }
- .tab-content-settings,
- #tab-about-about .popup-content-inner {
- padding-top: calc(5rem - var(--padding-small));
- }
-}
-@media screen and (max-width: 535px) and (display-mode: standalone) {
- .popup-header {
- padding-top: max(
- calc(env(safe-area-inset-top)),
- var(--padding) + 1rem
- );
- }
- .urgent-notice {
- padding-top: max(
- calc(env(safe-area-inset-top) - var(--padding-small)),
- var(--padding)
- );
- }
- #footer,
- .popup-tabs {
- padding-bottom: max(
- calc(env(safe-area-inset-bottom) + var(--padding-small)),
- var(--padding)
- );
- }
- .popup.small {
- padding-bottom: max(
- calc(env(safe-area-inset-bottom) + var(--padding-small)),
- var(--padding-dialog)
- );
- }
- .popup-content-inner,
- .tab-content-settings {
- padding-top: max(
- calc(env(safe-area-inset-top) + var(--padding) + var(--padding-small) + 2rem),
- calc(var(--padding) + 4rem - var(--padding-small))
- );
- padding-bottom: max(
- calc(env(safe-area-inset-bottom) + var(--padding) + 3rem),
- calc(var(--padding) + var(--padding-small) * 2 + 3rem)
- );
- }
- .tab-content-settings,
- #tab-about-about .popup-content-inner {
- padding-top: max(
- calc(env(safe-area-inset-top) + var(--padding) + var(--padding-small) * 2 + 3rem),
- calc(var(--padding) + 5rem)
- );
- }
- #picker-holder {
- padding-top: max(
- calc(env(safe-area-inset-top) + var(--padding) + 5rem),
- calc(var(--padding) * 2 + 6rem)
- );
- padding-bottom: max(
- calc(env(safe-area-inset-bottom) + var(--padding) + 2rem),
- calc(4rem - var(--padding) + var(--padding-small))
- );
- }
-
- .android .popup-header {
- padding-top: var(--padding);
- }
- .android .popup-content-inner,
- .android .tab-content-settings,
- .android #picker-holder {
- padding-bottom: calc(var(--padding) + 3.5rem);
- padding-top: calc(var(--padding) + 3rem - var(--padding-small));
- }
- .android .tab-content-settings,
- .android #tab-about-about .popup-content-inner {
- padding-top: calc(5rem - var(--padding-small));
- }
-}
diff --git a/src/front/cobalt.js b/src/front/cobalt.js
deleted file mode 100644
index ef5b448c..00000000
--- a/src/front/cobalt.js
+++ /dev/null
@@ -1,715 +0,0 @@
-const ua = navigator.userAgent.toLowerCase();
-const isIOS = ua.includes("iphone os") || (ua.includes("mac os") && navigator.maxTouchPoints > 0);
-const isAndroid = ua.includes("android");
-const isMobile = ua.includes("android") || isIOS;
-const isSafari = ua.includes("safari/");
-const isFirefox = ua.includes("firefox/");
-const isOldFirefox = ua.includes("firefox/") && ua.split("firefox/")[1].split('.')[0] < 103;
-
-const switchers = {
- "theme": ["auto", "light", "dark"],
- "vCodec": ["h264", "av1", "vp9"],
- "vQuality": ["720", "max", "2160", "1440", "1080", "480", "360", "240", "144"],
- "aFormat": ["mp3", "best", "ogg", "wav", "opus"],
- "audioMode": ["false", "true"],
- "filenamePattern": ["classic", "pretty", "basic", "nerdy"]
-}
-const checkboxes = [
- "alwaysVisibleButton",
- "downloadPopup",
- "fullTikTokAudio",
- "muteAudio",
- "reduceTransparency",
- "disableAnimations",
- "disableMetadata",
- "twitterGif",
- "plausible_ignore",
- "ytDub",
- "tiktokH265"
-]
-const bottomPopups = ["error", "download"]
-
-let store = {};
-
-const validLink = (link) => {
- try {
- return /^https:/i.test(new URL(link).protocol);
- } catch {
- return false
- }
-}
-
-const fixApiUrl = (url) => {
- return url.endsWith('/') ? url.slice(0, -1) : url
-}
-
-let apiURL = fixApiUrl(defaultApiUrl);
-
-const changeApi = (url) => {
- apiURL = fixApiUrl(url);
- return true
-}
-
-const eid = (id) => {
- return document.getElementById(id)
-}
-
-const sGet = (id) =>{
- return localStorage.getItem(id)
-}
-const sSet = (id, value) => {
- localStorage.setItem(id, value)
-}
-const lazyGet = (key) => {
- const value = sGet(key);
- if (key in switchers) {
- if (switchers[key][0] !== value)
- return value;
- } else if (checkboxes.includes(key)) {
- if (value === 'true')
- return true;
- }
-}
-
-const changeDownloadButton = (action, text) => {
- switch (action) {
- case "hidden": // hidden, but only visible when alwaysVisibleButton is true
- eid("download-button").disabled = true
- if (sGet("alwaysVisibleButton") === "true") {
- eid("download-button").value = '>>'
- eid("download-button").style.padding = '0 1rem'
- } else {
- eid("download-button").value = ''
- eid("download-button").style.padding = '0'
- }
- break;
- case "disabled":
- eid("download-button").disabled = true
- eid("download-button").value = text
- eid("download-button").style.padding = '0 1rem'
- break;
- default:
- eid("download-button").disabled = false
- eid("download-button").value = '>>'
- eid("download-button").style.padding = '0 1rem'
- break;
- }
-}
-
-const button = () => {
- let regexTest = validLink(eid("url-input-area").value);
-
- eid("url-clear").style.display = "none";
-
- if ((eid("url-input-area").value).length > 0) {
- eid("url-clear").style.display = "block";
- }
-
- if (regexTest) {
- changeDownloadButton()
- } else {
- changeDownloadButton("hidden")
- }
-}
-
-const clearInput = () => {
- eid("url-input-area").value = '';
- button();
-}
-
-const copy = (id, data) => {
- let target = document.getElementById(id);
- target.classList.add("text-backdrop");
-
- setTimeout(() => {
- target.classList.remove("text-backdrop")
- }, 600);
-
- if (data) {
- navigator.clipboard.writeText(data)
- } else {
- navigator.clipboard.writeText(e.innerText)
- }
-}
-
-const share = url => navigator?.share({ url }).catch(() => {});
-
-const preferredColorScheme = () => {
- let theme = "auto";
- let localTheme = sGet("theme");
- let isLightPreferred = false;
-
- if (localTheme) {
- theme = localTheme;
- }
- if (window.matchMedia) {
- isLightPreferred = window.matchMedia('(prefers-color-scheme: light)').matches;
- }
- if (theme === "auto") {
- theme = isLightPreferred ? "light" : "dark"
- }
-
- return theme
-}
-
-const changeStatusBarColor = () => {
- const theme = preferredColorScheme();
- const colors = {
- "dark": "#000000",
- "light": "#ffffff",
- "dark-popup": "#151515",
- "light-popup": "#ebebeb"
- }
-
- let state = store.isPopupOpen ? "dark-popup" : "dark";
-
- if (theme === "light") {
- state = store.isPopupOpen ? "light-popup" : "light";
- }
-
- document.querySelector('meta[name="theme-color"]').setAttribute('content', colors[state]);
-}
-const detectColorScheme = () => {
- document.documentElement.setAttribute("data-theme", preferredColorScheme());
- changeStatusBarColor();
-}
-
-if (window.matchMedia) {
- window.matchMedia('(prefers-color-scheme: light)').addEventListener('change', () => {
- changeStatusBarColor()
- detectColorScheme()
- })
-}
-
-const updateFilenamePreview = () => {
- let videoFilePreview = ``;
- let audioFilePreview = ``;
- let resMatch = {
- "max": "3840x2160",
- "2160": "3840x2160",
- "1440": "2560x1440",
- "1080": "1920x1080",
- "720": "1280x720",
- "480": "854x480",
- "360": "640x360",
- }
-
- switch(sGet("filenamePattern")) {
- case "classic":
- videoFilePreview = `youtube_dQw4w9WgXcQ_${resMatch[sGet('vQuality')]}_${sGet('vCodec')}`
- + `${sGet("muteAudio") === "true" ? "_mute" : ""}`
- + `.${sGet('vCodec') === "vp9" ? 'webm' : 'mp4'}`;
- audioFilePreview = `youtube_dQw4w9WgXcQ_audio`
- + `.${sGet('aFormat') !== "best" ? sGet('aFormat') : 'opus'}`;
- break;
- case "basic":
- videoFilePreview = `${loc.FilenamePreviewVideoTitle} `
- + `(${sGet('vQuality') === "max" ? "2160p" : `${sGet('vQuality')}p`}, `
- + `${sGet('vCodec')}${sGet("muteAudio") === "true" ? ", mute" : ""})`
- + `.${sGet('vCodec') === "vp9" ? 'webm' : 'mp4'}`;
- audioFilePreview = `${loc.FilenamePreviewAudioTitle} - ${loc.FilenamePreviewAudioAuthor}`
- + `.${sGet('aFormat') !== "best" ? sGet('aFormat') : 'opus'}`;
- break;
- case "pretty":
- videoFilePreview = `${loc.FilenamePreviewVideoTitle} `
- + `(${sGet('vQuality') === "max" ? "2160p" : `${sGet('vQuality')}p`}, ${sGet('vCodec')}, `
- + `${sGet("muteAudio") === "true" ? "mute, " : ""}youtube)`
- + `.${sGet('vCodec') === "vp9" ? 'webm' : 'mp4'}`;
- audioFilePreview = `${loc.FilenamePreviewAudioTitle} - ${loc.FilenamePreviewAudioAuthor} (soundcloud)`
- + `.${sGet('aFormat') !== "best" ? sGet('aFormat') : 'opus'}`;
- break;
- case "nerdy":
- videoFilePreview = `${loc.FilenamePreviewVideoTitle} `
- + `(${sGet('vQuality') === "max" ? "2160p" : `${sGet('vQuality')}p`}, ${sGet('vCodec')}, `
- + `${sGet("muteAudio") === "true" ? "mute, " : ""}youtube, dQw4w9WgXcQ)`
- + `.${sGet('vCodec') === "vp9" ? 'webm' : 'mp4'}`;
- audioFilePreview = `${loc.FilenamePreviewAudioTitle} - ${loc.FilenamePreviewAudioAuthor} `
- + `(soundcloud, 1242868615)`
- + `.${sGet('aFormat') !== "best" ? sGet('aFormat') : 'opus'}`;
- break;
- }
- eid("video-filename-text").innerHTML = videoFilePreview
- eid("audio-filename-text").innerHTML = audioFilePreview
-}
-
-const changeTab = (evnt, tabId, tabClass) => {
- if (tabId === "tab-settings-other") updateFilenamePreview();
-
- let tabcontent = document.getElementsByClassName(`tab-content-${tabClass}`);
- let tablinks = document.getElementsByClassName(`tab-${tabClass}`);
-
- for (let i = 0; i < tabcontent.length; i++) {
- tabcontent[i].dataset.enabled = "false";
- }
- for (let i = 0; i < tablinks.length; i++) {
- tablinks[i].dataset.enabled = "false";
- }
-
- evnt.currentTarget.dataset.enabled = "true";
- eid(tabId).dataset.enabled = "true";
- eid(tabId).parentElement.scrollTop = 0;
-}
-
-const expandCollapsible = (evnt) => {
- let classlist = evnt.currentTarget.parentNode.classList;
- let c = "expanded";
- !classlist.contains(c) ? classlist.add(c) : classlist.remove(c);
-}
-
-const hideAllPopups = () => {
- let filter = document.getElementsByClassName('popup');
- for (let i = 0; i < filter.length; i++) {
- filter[i].classList.remove("visible");
- }
- eid("popup-backdrop").classList.remove("visible");
- store.isPopupOpen = false;
-
- // clear the picker
- eid("picker-holder").innerHTML = '';
- eid("picker-download").href = '/';
- eid("picker-download").classList.remove("visible");
-}
-
-const popup = (type, action, text) => {
- if (action === 1) {
- hideAllPopups(); // hide the previous popup before showing a new one
- store.isPopupOpen = true;
-
- // if not a small popup, update status bar color to match the popup header
- if (!bottomPopups.includes(type)) changeStatusBarColor();
- switch (type) {
- case "about":
- let tabId = "about";
- if (text) tabId = text;
- eid(`tab-button-${type}-${tabId}`).click();
- break;
- case "settings":
- eid(`tab-button-${type}-video`).click();
- break;
- case "error":
- eid("desc-error").innerHTML = text;
- break;
- case "download":
- eid("pd-download").href = text;
- eid("pd-copy").setAttribute("onClick", `copy('pd-copy', '${text}')`);
- eid("pd-share").setAttribute("onClick", `share('${text}')`);
- if (navigator.canShare) eid("pd-share").style.display = "flex";
- break;
- case "picker":
- eid("picker-title").innerHTML = loc.MediaPickerTitle;
- eid("picker-subtitle").innerHTML = isMobile ? loc.MediaPickerExplanationPhone : loc.MediaPickerExplanationPC;
-
- switch (text.type) {
- case "images":
- eid("picker-holder").classList.remove("various");
-
- eid("picker-download").href = text.audio;
- eid("picker-download").classList.add("visible");
-
- for (let i in text.arr) {
- eid("picker-holder").innerHTML +=
- `` +
- `` +
- ``
- }
- break;
- default:
- eid("picker-holder").classList.add("various");
-
- for (let i in text.arr) {
- eid("picker-holder").innerHTML +=
- `` +
- `
`;
-
- try {
- if (!store.historyContent) {
- let j = await fetch(`/onDemand?blockId=${blockId}`).then(r => r.json()).catch(() => {});
- if (!j) throw new Error();
-
- if (j.status === "success") {
- store.historyContent = j.text
- }
- }
- eid(elementId).innerHTML =
- `
- ${store.historyContent}`;
- } catch {
- eid(elementId).innerHTML = store.historyButton;
- internetError()
- }
-}
-
-const restoreUpdateHistory = () => {
- eid("changelog-history").innerHTML = store.historyButton;
-}
-
-const loadSettings = () => {
- if (sGet("alwaysVisibleButton") === "true") {
- eid("alwaysVisibleButton").checked = true;
- eid("download-button").value = '>>'
- eid("download-button").style.padding = '0 1rem';
- }
- if (sGet("downloadPopup") === "true" && !isIOS) {
- eid("downloadPopup").checked = true;
- }
- if (sGet("reduceTransparency") === "true" || isOldFirefox) {
- eid("cobalt-body").classList.add('no-transparency');
- }
- if (sGet("disableAnimations") === "true") {
- eid("cobalt-body").classList.add('no-animation');
- }
- if (!isMobile) {
- eid("cobalt-body").classList.add('desktop');
- }
- if (isAndroid) {
- eid("cobalt-body").classList.add('android');
- }
- if (isIOS) {
- eid("download-switcher")
- .querySelector(".explanation")
- .innerHTML = loc.DownloadPopupDescriptionIOS;
- }
- for (let i = 0; i < checkboxes.length; i++) {
- try {
- if (sGet(checkboxes[i]) === "true") eid(checkboxes[i]).checked = true;
- }
- catch {
- console.error(`checkbox ${checkboxes[i]} failed to initialize`)
- }
- }
- for (let i in switchers) {
- changeSwitcher(i, sGet(i))
- }
- updateFilenamePreview()
-}
-
-window.onload = () => {
- loadCelebrationsEmoji();
-
- loadSettings();
- detectColorScheme();
-
- changeDownloadButton("hidden");
- eid("url-input-area").value = "";
-
- if (isIOS) {
- sSet("downloadPopup", "true");
- eid("downloadPopup-chkbx").style.display = "none";
- }
-
- eid("home").style.visibility = 'visible';
- eid("home").classList.toggle("visible");
-
- const pageQuery = new URLSearchParams(window.location.search);
- if (pageQuery.has("u") && validLink(pageQuery.get("u"))) {
- eid("url-input-area").value = pageQuery.get("u");
- button()
- }
- window.history.replaceState(null, '', window.location.pathname);
-
- // fix for animations not working in Safari
- if (isIOS) {
- document.addEventListener('touchstart', () => {}, true);
- }
-}
-
-eid("url-input-area").addEventListener("keydown", () => {
- button();
-})
-eid("url-input-area").addEventListener("keyup", (e) => {
- if (e.key === 'Enter') eid("download-button").click();
-})
-
-document.addEventListener("keydown", (event) => {
- if (event.key === "Tab") {
- eid("download-button").value = '>>'
- eid("download-button").style.padding = '0 1rem'
- }
-})
-document.onkeydown = (e) => {
- if (!store.isPopupOpen) {
- if (e.metaKey || e.ctrlKey || e.key === "/") eid("url-input-area").focus();
- if (e.key === "Escape" || e.key === "Clear") clearInput();
-
- if (e.target === eid("url-input-area")) return;
-
- // top buttons
- if (e.key === "D") pasteClipboard();
- if (e.key === "K") changeSwitcher('audioMode', 'false');
- if (e.key === "L") changeSwitcher('audioMode', 'true');
-
- // popups
- if (e.key === "B") popup('about', 1, 'about'); // open about
- if (e.key === "N") popup('about', 1, 'changelog'); // open changelog
- if (e.key === "M") popup('settings', 1);
-
- } else {
- if (e.key === "Escape") hideAllPopups();
- }
-}
diff --git a/src/front/emoji/3d/film_frames.png b/src/front/emoji/3d/film_frames.png
deleted file mode 100644
index 6522c5f7..00000000
Binary files a/src/front/emoji/3d/film_frames.png and /dev/null differ
diff --git a/src/front/emoji/3d/headphone.png b/src/front/emoji/3d/headphone.png
deleted file mode 100644
index b46173a2..00000000
Binary files a/src/front/emoji/3d/headphone.png and /dev/null differ
diff --git a/src/front/emoji/abacus.svg b/src/front/emoji/abacus.svg
deleted file mode 100644
index 6f9587c4..00000000
--- a/src/front/emoji/abacus.svg
+++ /dev/null
@@ -1,8 +0,0 @@
-
\ No newline at end of file
diff --git a/src/front/emoji/alien_monster.svg b/src/front/emoji/alien_monster.svg
deleted file mode 100644
index 66be00bd..00000000
--- a/src/front/emoji/alien_monster.svg
+++ /dev/null
@@ -1,9 +0,0 @@
-
\ No newline at end of file
diff --git a/src/front/emoji/biceps.svg b/src/front/emoji/biceps.svg
deleted file mode 100644
index 4de9e74e..00000000
--- a/src/front/emoji/biceps.svg
+++ /dev/null
@@ -1,7 +0,0 @@
-
diff --git a/src/front/emoji/bird.svg b/src/front/emoji/bird.svg
deleted file mode 100644
index 55cf0208..00000000
--- a/src/front/emoji/bird.svg
+++ /dev/null
@@ -1,6 +0,0 @@
-
diff --git a/src/front/emoji/boring_document.svg b/src/front/emoji/boring_document.svg
deleted file mode 100644
index ec3e642f..00000000
--- a/src/front/emoji/boring_document.svg
+++ /dev/null
@@ -1,8 +0,0 @@
-
\ No newline at end of file
diff --git a/src/front/emoji/bubbles.svg b/src/front/emoji/bubbles.svg
deleted file mode 100644
index e5bccc36..00000000
--- a/src/front/emoji/bubbles.svg
+++ /dev/null
@@ -1,30 +0,0 @@
-
diff --git a/src/front/emoji/cake.svg b/src/front/emoji/cake.svg
deleted file mode 100644
index c6de34d4..00000000
--- a/src/front/emoji/cake.svg
+++ /dev/null
@@ -1,11 +0,0 @@
-
diff --git a/src/front/emoji/candle.svg b/src/front/emoji/candle.svg
deleted file mode 100644
index f62a93d3..00000000
--- a/src/front/emoji/candle.svg
+++ /dev/null
@@ -1,7 +0,0 @@
-
diff --git a/src/front/emoji/cat.svg b/src/front/emoji/cat.svg
deleted file mode 100644
index a29d581e..00000000
--- a/src/front/emoji/cat.svg
+++ /dev/null
@@ -1,13 +0,0 @@
-
diff --git a/src/front/emoji/cat_crying.svg b/src/front/emoji/cat_crying.svg
deleted file mode 100644
index 896ae898..00000000
--- a/src/front/emoji/cat_crying.svg
+++ /dev/null
@@ -1,14 +0,0 @@
-
\ No newline at end of file
diff --git a/src/front/emoji/cat_flabbergasted.svg b/src/front/emoji/cat_flabbergasted.svg
deleted file mode 100644
index 92f72427..00000000
--- a/src/front/emoji/cat_flabbergasted.svg
+++ /dev/null
@@ -1,21 +0,0 @@
-
\ No newline at end of file
diff --git a/src/front/emoji/cat_grin.svg b/src/front/emoji/cat_grin.svg
deleted file mode 100644
index 4b7cbb06..00000000
--- a/src/front/emoji/cat_grin.svg
+++ /dev/null
@@ -1,13 +0,0 @@
-
\ No newline at end of file
diff --git a/src/front/emoji/cat_smile.svg b/src/front/emoji/cat_smile.svg
deleted file mode 100644
index 06ff249c..00000000
--- a/src/front/emoji/cat_smile.svg
+++ /dev/null
@@ -1,13 +0,0 @@
-
\ No newline at end of file
diff --git a/src/front/emoji/christmas_tree.svg b/src/front/emoji/christmas_tree.svg
deleted file mode 100644
index dead8216..00000000
--- a/src/front/emoji/christmas_tree.svg
+++ /dev/null
@@ -1,11 +0,0 @@
-
diff --git a/src/front/emoji/clapper_board.svg b/src/front/emoji/clapper_board.svg
deleted file mode 100644
index 8bcf482b..00000000
--- a/src/front/emoji/clapper_board.svg
+++ /dev/null
@@ -1,13 +0,0 @@
-
diff --git a/src/front/emoji/clipboard.svg b/src/front/emoji/clipboard.svg
deleted file mode 100644
index b4d28229..00000000
--- a/src/front/emoji/clipboard.svg
+++ /dev/null
@@ -1,11 +0,0 @@
-
diff --git a/src/front/emoji/crystal_ball.svg b/src/front/emoji/crystal_ball.svg
deleted file mode 100644
index d2a7f670..00000000
--- a/src/front/emoji/crystal_ball.svg
+++ /dev/null
@@ -1,7 +0,0 @@
-
diff --git a/src/front/emoji/dog.svg b/src/front/emoji/dog.svg
deleted file mode 100644
index 03056a1f..00000000
--- a/src/front/emoji/dog.svg
+++ /dev/null
@@ -1,11 +0,0 @@
-
diff --git a/src/front/emoji/dragon_face.svg b/src/front/emoji/dragon_face.svg
deleted file mode 100644
index 861ae074..00000000
--- a/src/front/emoji/dragon_face.svg
+++ /dev/null
@@ -1,11 +0,0 @@
-
diff --git a/src/front/emoji/dragon_face_wukko.svg b/src/front/emoji/dragon_face_wukko.svg
deleted file mode 100644
index c389f4c8..00000000
--- a/src/front/emoji/dragon_face_wukko.svg
+++ /dev/null
@@ -1,11 +0,0 @@
-
diff --git a/src/front/emoji/elephant.svg b/src/front/emoji/elephant.svg
deleted file mode 100644
index 3f96a89a..00000000
--- a/src/front/emoji/elephant.svg
+++ /dev/null
@@ -1,8 +0,0 @@
-
diff --git a/src/front/emoji/email.svg b/src/front/emoji/email.svg
deleted file mode 100644
index 144c9534..00000000
--- a/src/front/emoji/email.svg
+++ /dev/null
@@ -1,9 +0,0 @@
-
\ No newline at end of file
diff --git a/src/front/emoji/film_frames.svg b/src/front/emoji/film_frames.svg
deleted file mode 100644
index 7471d431..00000000
--- a/src/front/emoji/film_frames.svg
+++ /dev/null
@@ -1,4 +0,0 @@
-
\ No newline at end of file
diff --git a/src/front/emoji/gear.svg b/src/front/emoji/gear.svg
deleted file mode 100644
index 8351a33a..00000000
--- a/src/front/emoji/gear.svg
+++ /dev/null
@@ -1,5 +0,0 @@
-
diff --git a/src/front/emoji/headphone.svg b/src/front/emoji/headphone.svg
deleted file mode 100644
index 1c9b6702..00000000
--- a/src/front/emoji/headphone.svg
+++ /dev/null
@@ -1,7 +0,0 @@
-
\ No newline at end of file
diff --git a/src/front/emoji/keyboard.svg b/src/front/emoji/keyboard.svg
deleted file mode 100644
index f6cb218b..00000000
--- a/src/front/emoji/keyboard.svg
+++ /dev/null
@@ -1,4 +0,0 @@
-
diff --git a/src/front/emoji/link.svg b/src/front/emoji/link.svg
deleted file mode 100644
index c3d86605..00000000
--- a/src/front/emoji/link.svg
+++ /dev/null
@@ -1,4 +0,0 @@
-
\ No newline at end of file
diff --git a/src/front/emoji/locked.svg b/src/front/emoji/locked.svg
deleted file mode 100644
index 98e9e0e7..00000000
--- a/src/front/emoji/locked.svg
+++ /dev/null
@@ -1,5 +0,0 @@
-
\ No newline at end of file
diff --git a/src/front/emoji/loudspeaker.svg b/src/front/emoji/loudspeaker.svg
deleted file mode 100644
index 6acd5873..00000000
--- a/src/front/emoji/loudspeaker.svg
+++ /dev/null
@@ -1,6 +0,0 @@
-
diff --git a/src/front/emoji/magic_wand.svg b/src/front/emoji/magic_wand.svg
deleted file mode 100644
index b10883b6..00000000
--- a/src/front/emoji/magic_wand.svg
+++ /dev/null
@@ -1,5 +0,0 @@
-
diff --git a/src/front/emoji/magnifying_glass.svg b/src/front/emoji/magnifying_glass.svg
deleted file mode 100644
index 905da556..00000000
--- a/src/front/emoji/magnifying_glass.svg
+++ /dev/null
@@ -1,5 +0,0 @@
-
\ No newline at end of file
diff --git a/src/front/emoji/mailbox.svg b/src/front/emoji/mailbox.svg
deleted file mode 100644
index 5dfd70b5..00000000
--- a/src/front/emoji/mailbox.svg
+++ /dev/null
@@ -1,12 +0,0 @@
-
diff --git a/src/front/emoji/mending_heart.svg b/src/front/emoji/mending_heart.svg
deleted file mode 100644
index 3b647fa7..00000000
--- a/src/front/emoji/mending_heart.svg
+++ /dev/null
@@ -1,5 +0,0 @@
-
\ No newline at end of file
diff --git a/src/front/emoji/money_with_wings.svg b/src/front/emoji/money_with_wings.svg
deleted file mode 100644
index 56d0cb0c..00000000
--- a/src/front/emoji/money_with_wings.svg
+++ /dev/null
@@ -1,12 +0,0 @@
-
diff --git a/src/front/emoji/musical_notes.svg b/src/front/emoji/musical_notes.svg
deleted file mode 100644
index f66414f0..00000000
--- a/src/front/emoji/musical_notes.svg
+++ /dev/null
@@ -1,5 +0,0 @@
-
diff --git a/src/front/emoji/newspaper.svg b/src/front/emoji/newspaper.svg
deleted file mode 100644
index ebe0b5fd..00000000
--- a/src/front/emoji/newspaper.svg
+++ /dev/null
@@ -1,5 +0,0 @@
-
\ No newline at end of file
diff --git a/src/front/emoji/octopus.svg b/src/front/emoji/octopus.svg
deleted file mode 100644
index b8c6e906..00000000
--- a/src/front/emoji/octopus.svg
+++ /dev/null
@@ -1,12 +0,0 @@
-
diff --git a/src/front/emoji/party_popper.svg b/src/front/emoji/party_popper.svg
deleted file mode 100644
index 93113d0f..00000000
--- a/src/front/emoji/party_popper.svg
+++ /dev/null
@@ -1,15 +0,0 @@
-
diff --git a/src/front/emoji/pinata.svg b/src/front/emoji/pinata.svg
deleted file mode 100644
index cf260701..00000000
--- a/src/front/emoji/pinata.svg
+++ /dev/null
@@ -1,16 +0,0 @@
-
diff --git a/src/front/emoji/pumpkin.svg b/src/front/emoji/pumpkin.svg
deleted file mode 100644
index 3dcf031a..00000000
--- a/src/front/emoji/pumpkin.svg
+++ /dev/null
@@ -1,7 +0,0 @@
-
diff --git a/src/front/emoji/question_mark.svg b/src/front/emoji/question_mark.svg
deleted file mode 100644
index 3c7e887a..00000000
--- a/src/front/emoji/question_mark.svg
+++ /dev/null
@@ -1,4 +0,0 @@
-
diff --git a/src/front/emoji/sparkles.svg b/src/front/emoji/sparkles.svg
deleted file mode 100644
index e9702d09..00000000
--- a/src/front/emoji/sparkles.svg
+++ /dev/null
@@ -1,5 +0,0 @@
-
diff --git a/src/front/emoji/sparkling_heart.svg b/src/front/emoji/sparkling_heart.svg
deleted file mode 100644
index b5dd6eb2..00000000
--- a/src/front/emoji/sparkling_heart.svg
+++ /dev/null
@@ -1,5 +0,0 @@
-
\ No newline at end of file
diff --git a/src/front/emoji/wrench.svg b/src/front/emoji/wrench.svg
deleted file mode 100644
index b186d3b3..00000000
--- a/src/front/emoji/wrench.svg
+++ /dev/null
@@ -1,3 +0,0 @@
-
diff --git a/src/front/fonts/files/notosansmono_3dVQ.woff2 b/src/front/fonts/files/notosansmono_3dVQ.woff2
deleted file mode 100644
index 1174c362..00000000
Binary files a/src/front/fonts/files/notosansmono_3dVQ.woff2 and /dev/null differ
diff --git a/src/front/fonts/files/notosansmono_7dVXQQ.woff2 b/src/front/fonts/files/notosansmono_7dVXQQ.woff2
deleted file mode 100644
index e9fcb07d..00000000
Binary files a/src/front/fonts/files/notosansmono_7dVXQQ.woff2 and /dev/null differ
diff --git a/src/front/fonts/files/notosansmono_DdVXQQ.woff2 b/src/front/fonts/files/notosansmono_DdVXQQ.woff2
deleted file mode 100644
index 28bca6ff..00000000
Binary files a/src/front/fonts/files/notosansmono_DdVXQQ.woff2 and /dev/null differ
diff --git a/src/front/fonts/files/notosansmono_HdVXQQ.woff2 b/src/front/fonts/files/notosansmono_HdVXQQ.woff2
deleted file mode 100644
index 95050fe6..00000000
Binary files a/src/front/fonts/files/notosansmono_HdVXQQ.woff2 and /dev/null differ
diff --git a/src/front/fonts/files/notosansmono_LdVXQQ.woff2 b/src/front/fonts/files/notosansmono_LdVXQQ.woff2
deleted file mode 100644
index 137ea72c..00000000
Binary files a/src/front/fonts/files/notosansmono_LdVXQQ.woff2 and /dev/null differ
diff --git a/src/front/fonts/files/notosansmono_PdVXQQ.woff2 b/src/front/fonts/files/notosansmono_PdVXQQ.woff2
deleted file mode 100644
index e3267a5e..00000000
Binary files a/src/front/fonts/files/notosansmono_PdVXQQ.woff2 and /dev/null differ
diff --git a/src/front/fonts/files/notosansmono_ndVXQQ.woff2 b/src/front/fonts/files/notosansmono_ndVXQQ.woff2
deleted file mode 100644
index bb374b0a..00000000
Binary files a/src/front/fonts/files/notosansmono_ndVXQQ.woff2 and /dev/null differ
diff --git a/src/front/fonts/notosansmono.css b/src/front/fonts/notosansmono.css
deleted file mode 100644
index 827b4f61..00000000
--- a/src/front/fonts/notosansmono.css
+++ /dev/null
@@ -1 +0,0 @@
-@font-face{font-family:'Noto Sans Mono';font-style:normal;font-weight:500;font-stretch:100%;font-display:swap;src:url('files/notosansmono_DdVXQQ.woff2') format('woff2');unicode-range:U+0460-052F, U+1C80-1C88, U+20B4, U+2DE0-2DFF, U+A640-A69F, U+FE2E-FE2F}@font-face{font-family:'Noto Sans Mono';font-style:normal;font-weight:500;font-stretch:100%;font-display:swap;src:url('files/notosansmono_ndVXQQ.woff2') format('woff2');unicode-range:U+0400-045F, U+0490-0491, U+04B0-04B1, U+2116}@font-face{font-family:'Noto Sans Mono';font-style:normal;font-weight:500;font-stretch:100%;font-display:swap;src:url('files/notosansmono_HdVXQQ.woff2') format('woff2');unicode-range:U+1F00-1FFF}@font-face{font-family:'Noto Sans Mono';font-style:normal;font-weight:500;font-stretch:100%;font-display:swap;src:url('files/notosansmono_7dVXQQ.woff2') format('woff2');unicode-range:U+0370-03FF}@font-face{font-family:'Noto Sans Mono';font-style:normal;font-weight:500;font-stretch:100%;font-display:swap;src:url('files/notosansmono_LdVXQQ.woff2') format('woff2');unicode-range:U+0102-0103, U+0110-0111, U+0128-0129, U+0168-0169, U+01A0-01A1, U+01AF-01B0, U+1EA0-1EF9, U+20AB}@font-face{font-family:'Noto Sans Mono';font-style:normal;font-weight:500;font-stretch:100%;font-display:swap;src:url('files/notosansmono_PdVXQQ.woff2') format('woff2');unicode-range:U+0100-024F, U+0259, U+1E00-1EFF, U+2020, U+20A0-20AB, U+20AD-20CF, U+2113, U+2C60-2C7F, U+A720-A7FF}@font-face{font-family:'Noto Sans Mono';font-style:normal;font-weight:500;font-stretch:100%;font-display:swap;src:url('files/notosansmono_3dVQ.woff2') format('woff2');unicode-range:U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+2000-206F, U+2074, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD}
\ No newline at end of file
diff --git a/src/front/icons/android-chrome-192x192.png b/src/front/icons/android-chrome-192x192.png
deleted file mode 100644
index 0d3ac83a..00000000
Binary files a/src/front/icons/android-chrome-192x192.png and /dev/null differ
diff --git a/src/front/icons/android-chrome-512x512.png b/src/front/icons/android-chrome-512x512.png
deleted file mode 100644
index d1777d48..00000000
Binary files a/src/front/icons/android-chrome-512x512.png and /dev/null differ
diff --git a/src/front/icons/apple-touch-icon.png b/src/front/icons/apple-touch-icon.png
deleted file mode 100644
index b2abfa63..00000000
Binary files a/src/front/icons/apple-touch-icon.png and /dev/null differ
diff --git a/src/front/icons/favicon-16x16.png b/src/front/icons/favicon-16x16.png
deleted file mode 100644
index 94f9c1a9..00000000
Binary files a/src/front/icons/favicon-16x16.png and /dev/null differ
diff --git a/src/front/icons/favicon-32x32.png b/src/front/icons/favicon-32x32.png
deleted file mode 100644
index b4e9203f..00000000
Binary files a/src/front/icons/favicon-32x32.png and /dev/null differ
diff --git a/src/front/icons/favicon.ico b/src/front/icons/favicon.ico
deleted file mode 100644
index 1b08e4bb..00000000
Binary files a/src/front/icons/favicon.ico and /dev/null differ
diff --git a/src/front/icons/generic.png b/src/front/icons/generic.png
deleted file mode 100644
index d1777d48..00000000
Binary files a/src/front/icons/generic.png and /dev/null differ
diff --git a/src/front/icons/maskable/128.png b/src/front/icons/maskable/128.png
deleted file mode 100644
index e8213cfe..00000000
Binary files a/src/front/icons/maskable/128.png and /dev/null differ
diff --git a/src/front/icons/maskable/192.png b/src/front/icons/maskable/192.png
deleted file mode 100644
index 8268d89a..00000000
Binary files a/src/front/icons/maskable/192.png and /dev/null differ
diff --git a/src/front/icons/maskable/384.png b/src/front/icons/maskable/384.png
deleted file mode 100644
index 483e42ff..00000000
Binary files a/src/front/icons/maskable/384.png and /dev/null differ
diff --git a/src/front/icons/maskable/48.png b/src/front/icons/maskable/48.png
deleted file mode 100644
index 02a5bca0..00000000
Binary files a/src/front/icons/maskable/48.png and /dev/null differ
diff --git a/src/front/icons/maskable/512.png b/src/front/icons/maskable/512.png
deleted file mode 100644
index bb4af2f3..00000000
Binary files a/src/front/icons/maskable/512.png and /dev/null differ
diff --git a/src/front/icons/maskable/72.png b/src/front/icons/maskable/72.png
deleted file mode 100644
index 903f6bd5..00000000
Binary files a/src/front/icons/maskable/72.png and /dev/null differ
diff --git a/src/front/icons/maskable/96.png b/src/front/icons/maskable/96.png
deleted file mode 100644
index c4b1ae60..00000000
Binary files a/src/front/icons/maskable/96.png and /dev/null differ
diff --git a/src/front/icons/pattern.png b/src/front/icons/pattern.png
deleted file mode 100644
index dfaef1c8..00000000
Binary files a/src/front/icons/pattern.png and /dev/null differ
diff --git a/src/front/manifest.webmanifest b/src/front/manifest.webmanifest
deleted file mode 100644
index 3777ca6d..00000000
--- a/src/front/manifest.webmanifest
+++ /dev/null
@@ -1,75 +0,0 @@
-{
- "name": "cobalt",
- "short_name": "cobalt",
- "start_url": "/",
- "icons": [
- {
- "src": "/icons/android-chrome-192x192.png",
- "sizes": "192x192",
- "type": "image/png"
- },
- {
- "src": "/icons/android-chrome-512x512.png",
- "sizes": "512x512",
- "type": "image/png"
- },
- {
- "src": "/icons/generic.png",
- "sizes": "512x512",
- "type": "image/png",
- "purpose": "any"
- },
- {
- "src": "/icons/maskable/48.png",
- "sizes": "48x48",
- "type": "image/png",
- "purpose": "maskable"
- },
- {
- "src": "/icons/maskable/72.png",
- "sizes": "72x72",
- "type": "image/png",
- "purpose": "maskable"
- },
- {
- "src": "/icons/maskable/96.png",
- "sizes": "96x96",
- "type": "image/png",
- "purpose": "maskable"
- },
- {
- "src": "/icons/maskable/128.png",
- "sizes": "128x128",
- "type": "image/png",
- "purpose": "maskable"
- },
- {
- "src": "/icons/maskable/192.png",
- "sizes": "192x192",
- "type": "image/png",
- "purpose": "maskable"
- },
- {
- "src": "/icons/maskable/384.png",
- "sizes": "384x384",
- "type": "image/png",
- "purpose": "maskable"
- },
- {
- "src": "/icons/maskable/512.png",
- "sizes": "512x512",
- "type": "image/png",
- "purpose": "maskable"
- }
- ],
- "share_target": {
- "action": "/",
- "params": {
- "text": "u",
- "url": "u"
- }
- },
- "theme_color": "#000000",
- "background_color": "#000000",
- "display": "standalone"
-}
diff --git a/src/front/robots.txt b/src/front/robots.txt
deleted file mode 100644
index a5218222..00000000
--- a/src/front/robots.txt
+++ /dev/null
@@ -1,8 +0,0 @@
-User-Agent: *
-Disallow: /emoji/
-Disallow: /fonts/
-Disallow: /icons/
-Disallow: /sponsors/
-Disallow: /updateBanners/
-Disallow: /*.js
-Disallow: /*.css
diff --git a/src/front/sponsors/royale.svg b/src/front/sponsors/royale.svg
deleted file mode 100644
index c0338038..00000000
--- a/src/front/sponsors/royale.svg
+++ /dev/null
@@ -1 +0,0 @@
-
\ No newline at end of file
diff --git a/src/front/updateBanners/bettertogether.webp b/src/front/updateBanners/bettertogether.webp
deleted file mode 100644
index a1e03806..00000000
Binary files a/src/front/updateBanners/bettertogether.webp and /dev/null differ
diff --git a/src/front/updateBanners/catmakeup.webp b/src/front/updateBanners/catmakeup.webp
deleted file mode 100644
index baaf8e04..00000000
Binary files a/src/front/updateBanners/catmakeup.webp and /dev/null differ
diff --git a/src/front/updateBanners/catphonestand.webp b/src/front/updateBanners/catphonestand.webp
deleted file mode 100644
index 9a641785..00000000
Binary files a/src/front/updateBanners/catphonestand.webp and /dev/null differ
diff --git a/src/front/updateBanners/catroomba.webp b/src/front/updateBanners/catroomba.webp
deleted file mode 100644
index a94eeeb0..00000000
Binary files a/src/front/updateBanners/catroomba.webp and /dev/null differ
diff --git a/src/front/updateBanners/catsleep.webp b/src/front/updateBanners/catsleep.webp
deleted file mode 100644
index a63d1f5c..00000000
Binary files a/src/front/updateBanners/catsleep.webp and /dev/null differ
diff --git a/src/front/updateBanners/catspeed.webp b/src/front/updateBanners/catspeed.webp
deleted file mode 100644
index b2bfda1c..00000000
Binary files a/src/front/updateBanners/catspeed.webp and /dev/null differ
diff --git a/src/front/updateBanners/catswitchboxes.webp b/src/front/updateBanners/catswitchboxes.webp
deleted file mode 100644
index d4ae2bc3..00000000
Binary files a/src/front/updateBanners/catswitchboxes.webp and /dev/null differ
diff --git a/src/front/updateBanners/cattired.webp b/src/front/updateBanners/cattired.webp
deleted file mode 100644
index f108ac89..00000000
Binary files a/src/front/updateBanners/cattired.webp and /dev/null differ
diff --git a/src/front/updateBanners/developers.webp b/src/front/updateBanners/developers.webp
deleted file mode 100644
index 3316a7f5..00000000
Binary files a/src/front/updateBanners/developers.webp and /dev/null differ
diff --git a/src/front/updateBanners/happymeowth.webp b/src/front/updateBanners/happymeowth.webp
deleted file mode 100644
index 0c8f78b8..00000000
Binary files a/src/front/updateBanners/happymeowth.webp and /dev/null differ
diff --git a/src/front/updateBanners/meowth7eleven.webp b/src/front/updateBanners/meowth7eleven.webp
deleted file mode 100644
index f44722d8..00000000
Binary files a/src/front/updateBanners/meowth7eleven.webp and /dev/null differ
diff --git a/src/front/updateBanners/meowthball.webp b/src/front/updateBanners/meowthball.webp
deleted file mode 100644
index 20a4e150..00000000
Binary files a/src/front/updateBanners/meowthball.webp and /dev/null differ
diff --git a/src/front/updateBanners/meowthbusinessman.webp b/src/front/updateBanners/meowthbusinessman.webp
deleted file mode 100644
index c7313895..00000000
Binary files a/src/front/updateBanners/meowthbusinessman.webp and /dev/null differ
diff --git a/src/front/updateBanners/meowthcenter.webp b/src/front/updateBanners/meowthcenter.webp
deleted file mode 100644
index 8690882b..00000000
Binary files a/src/front/updateBanners/meowthcenter.webp and /dev/null differ
diff --git a/src/front/updateBanners/meowthcooking.webp b/src/front/updateBanners/meowthcooking.webp
deleted file mode 100644
index a0bea02a..00000000
Binary files a/src/front/updateBanners/meowthcooking.webp and /dev/null differ
diff --git a/src/front/updateBanners/meowthhammer.webp b/src/front/updateBanners/meowthhammer.webp
deleted file mode 100644
index ed3c97bb..00000000
Binary files a/src/front/updateBanners/meowthhammer.webp and /dev/null differ
diff --git a/src/front/updateBanners/meowthpolishegg.webp b/src/front/updateBanners/meowthpolishegg.webp
deleted file mode 100644
index e1eff23d..00000000
Binary files a/src/front/updateBanners/meowthpolishegg.webp and /dev/null differ
diff --git a/src/front/updateBanners/meowthproductions.webp b/src/front/updateBanners/meowthproductions.webp
deleted file mode 100644
index 56ef2568..00000000
Binary files a/src/front/updateBanners/meowthproductions.webp and /dev/null differ
diff --git a/src/front/updateBanners/meowthsnap.webp b/src/front/updateBanners/meowthsnap.webp
deleted file mode 100644
index a1b94d53..00000000
Binary files a/src/front/updateBanners/meowthsnap.webp and /dev/null differ
diff --git a/src/front/updateBanners/meowthstrong.webp b/src/front/updateBanners/meowthstrong.webp
deleted file mode 100644
index 96ab3052..00000000
Binary files a/src/front/updateBanners/meowthstrong.webp and /dev/null differ
diff --git a/src/front/updateBanners/newdomain.webp b/src/front/updateBanners/newdomain.webp
deleted file mode 100644
index 256784a2..00000000
Binary files a/src/front/updateBanners/newdomain.webp and /dev/null differ
diff --git a/src/front/updateBanners/onemillionr.webp b/src/front/updateBanners/onemillionr.webp
deleted file mode 100644
index 69ee499e..00000000
Binary files a/src/front/updateBanners/onemillionr.webp and /dev/null differ
diff --git a/src/front/updateBanners/shutup.webp b/src/front/updateBanners/shutup.webp
deleted file mode 100644
index e0a08a7d..00000000
Binary files a/src/front/updateBanners/shutup.webp and /dev/null differ
diff --git a/src/front/updateBanners/twitchupdate.webp b/src/front/updateBanners/twitchupdate.webp
deleted file mode 100644
index 45bd622e..00000000
Binary files a/src/front/updateBanners/twitchupdate.webp and /dev/null differ
diff --git a/src/front/updateBanners/valentines.webp b/src/front/updateBanners/valentines.webp
deleted file mode 100644
index 8e18cd1b..00000000
Binary files a/src/front/updateBanners/valentines.webp and /dev/null differ
diff --git a/src/localization/languages/en.json b/src/localization/languages/en.json
deleted file mode 100644
index b0987337..00000000
--- a/src/localization/languages/en.json
+++ /dev/null
@@ -1,160 +0,0 @@
-{
- "name": "english",
- "substrings": {
- "ContactLink": "check the status page or create an issue on github"
- },
- "strings": {
- "AppTitleCobalt": "cobalt",
- "LinkInput": "paste the link here",
- "AboutSummary": "cobalt is your go-to place for downloads from social and media platforms. zero ads, trackers, or other creepy bullshit. simply paste a share link and you're ready to rock!",
- "EmbedBriefDescription": "save what you love. no ads, trackers, or other creepy bullshit.",
- "MadeWithLove": "made with <3 by imput",
- "AccessibilityInputArea": "link input area",
- "AccessibilityOpenAbout": "open about popup",
- "AccessibilityDownloadButton": "download button",
- "AccessibilityOpenSettings": "open settings popup",
- "AccessibilityOpenDonate": "open donation popup",
- "TitlePopupAbout": "what's cobalt?",
- "TitlePopupSettings": "settings",
- "TitlePopupChangelog": "what's new?",
- "TitlePopupDonate": "support cobalt",
- "TitlePopupDownload": "how to save?",
- "ErrorSomethingWentWrong": "something went wrong and i couldn't get anything for you. try again, but if issue persists, {ContactLink}.",
- "ErrorUnsupported": "it seems like this service is not supported yet or your link is invalid. have you pasted the right link?",
- "ErrorBrokenLink": "{s} is supported, but something is wrong with your link. maybe you didn't copy it fully?",
- "ErrorNoLink": "i can't guess what you want to download! please give me a link :(",
- "ErrorPageRenderFail": "if you're reading this, then there's something wrong with the page renderer. please {ContactLink}. make sure to provide the domain this error is present on and current commit hash ({s}). thank you in advance :D",
- "ErrorRateLimit": "you're making too many requests. try again in a minute!",
- "ErrorCouldntFetch": "i couldn't find anything about this link. check if it works and try again! some content may be region restricted, so keep that in mind.",
- "ErrorLengthLimit": "i can't process videos longer than {s} minutes, so pick something shorter instead!",
- "ErrorBadFetch": "something went wrong when i tried getting info about your link. are you sure it works? check if it does, and try again.",
- "ErrorNoInternet": "there's no internet or cobalt api is temporarily unavailable. check your connection and try again.",
- "ErrorCantConnectToServiceAPI": "i couldn't connect to the service api. maybe it's down, or cobalt got blocked. try again, but if error persists, {ContactLink}.",
- "ErrorEmptyDownload": "i don't see anything i could download by your link. try a different one!",
- "ErrorLiveVideo": "this is a live video, i am yet to learn how to look into future. wait for the stream to finish and try again!",
- "SettingsAppearanceSubtitle": "appearance",
- "SettingsThemeSubtitle": "theme",
- "SettingsFormatSubtitle": "format",
- "SettingsQualitySubtitle": "quality",
- "SettingsThemeAuto": "auto",
- "SettingsThemeLight": "light",
- "SettingsThemeDark": "dark",
- "SettingsKeepDownloadButton": "keep >> visible",
- "AccessibilityKeepDownloadButton": "keep the download button always visible",
- "SettingsEnableDownloadPopup": "ask how to save",
- "AccessibilityEnableDownloadPopup": "ask what to do with downloads",
- "SettingsQualityDescription": "if selected quality isn't available, closest one is used instead.",
- "NoScriptMessage": "cobalt uses javascript for api requests and interactive interface. you have to allow javascript to use this site. there are no pesty scripts, pinky promise.",
- "DownloadPopupDescriptionIOS": "how to save to photos:\n1. add save to photos shortcut.\n2. press \"share\" button above this text.\n3. select \"save to photos\" in the share sheet.\n\nhow to save to files:\n1. add save to files shortcut.\n2. press \"share\" button above this text.\n3. select \"save to files\" in the share sheet.\n4. select a folder to save the file to and press \"open\".\n\nboth shortcuts can only be used from the cobalt web app.",
- "DownloadPopupDescription": "download button opens a new tab with requested file. you can disable this popup in settings.",
- "ClickToCopy": "press to copy",
- "Download": "download",
- "CopyURL": "copy",
- "AboutTab": "about",
- "ChangelogTab": "changelog",
- "DonationsTab": "donations",
- "SettingsVideoTab": "video",
- "SettingsAudioTab": "audio",
- "SettingsOtherTab": "other",
- "ChangelogLastMajor": "current version & commit",
- "AccessibilityModeToggle": "toggle download mode",
- "DonateLinksDescription": "this is the best way to donate if you want me to receive your donation directly.",
- "SettingsAudioFormatBest": "best",
- "SettingsAudioFormatDescription": "when \"best\" format is selected, you get audio the way it is on service's side. it's not re-encoded. everything else will be re-encoded.",
- "Keyphrase": "save what you love",
- "ErrorPopupCloseButton": "got it",
- "ErrorLengthAudioConvert": "i can't convert audio longer than {s} minutes. pick \"best\" format if you want to avoid limitations!",
- "SettingsAudioFullTikTok": "full audio",
- "SettingsAudioFullTikTokDescription": "downloads original sound used in the video without any additional changes by the post's author.",
- "ErrorCantGetID": "i couldn't get the full info from the shortened link. make sure it works or try a full one! if issue persists, {ContactLink}.",
- "ErrorNoVideosInTweet": "i couldn't find any media content in this tweet. try another one!",
- "ImagePickerTitle": "pick images to download",
- "ImagePickerDownloadAudio": "download audio",
- "ImagePickerExplanationPC": "right click an image to save it.",
- "ImagePickerExplanationPhone": "press and hold an image to save it.",
- "ErrorNoUrlReturned": "i didn't get a download link from the server. this should never happen. try again, but if it still doesn't work, {ContactLink}.",
- "ErrorUnknownStatus": "i received a response i can't process. this should never happen. try again, but if it still doesn't work, {ContactLink}.",
- "PasteFromClipboard": "paste",
- "ChangelogOlder": "previous versions",
- "ChangelogPressToExpand": "expand",
- "Miscellaneous": "miscellaneous",
- "ModeToggleAuto": "auto",
- "ModeToggleAudio": "audio",
- "MediaPickerTitle": "pick what to save",
- "MediaPickerExplanationPC": "click or right click to download what you want.",
- "MediaPickerExplanationPhone": "press or press and hold to download what you want.",
- "TwitterSpaceWasntRecorded": "this twitter space wasn't recorded, so there's nothing to download. try another one!",
- "ErrorCantProcess": "i couldn't process your request :(\nyou can try again, but if issue persists, please {ContactLink}.",
- "ChangelogPressToHide": "collapse",
- "Donate": "donate",
- "DonateSub": "help it stay online",
- "DonateExplanation": "cobalt doesn't shove ads in your face and doesn't sell your personal data, meaning that it's completely free to use for everyone. but development and maintenance of a media-heavy service used by over 750k people is quite costly. both in terms of time and money.\n\nif cobalt helped you in the past and you want to keep it growing and evolving, you can return the favor by making a donation!\n\nyour donation will help all cobalt users: educators, students, content creators, artists, musicians, and many, many more!\n\nin past, donations have let cobalt:\n*; increase stability and uptime to nearly 100%.\n*; speed up ALL downloads, especially heavier ones.\n*; open the api for free public use.\n*; withstand several huge user influxes with 0 downtime.\n*; add resource-intensive features (such as gif conversion).\n*; continue improving our infrastructure.\n*; keep developers happy.\n\nevery cent matters and is extremely appreciated, you can truly make a difference!\n\nif you can't donate, share cobalt with a friend! we don't get ads anywhere, so cobalt is spread by word of mouth.\nsharing is the easiest way to help achieve the goal of better internet for everyone.",
- "DonateVia": "donate via",
- "SettingsVideoMute": "mute audio",
- "SettingsVideoMuteExplanation": "removes audio from video downloads when possible.",
- "ErrorSoundCloudNoClientId": "i couldn't get the temporary token that's required to download songs from soundcloud. try again, but if issue persists, {ContactLink}.",
- "CollapseServices": "supported services",
- "CollapseSupport": "support & source code",
- "CollapsePrivacy": "privacy policy",
- "ServicesNote": "this list is not final and keeps expanding over time, make sure to check it once in a while!",
- "FollowSupport": "keep in touch with cobalt for news, support, and more:",
- "SourceCode": "explore source code, report issues, star or fork the repo:",
- "PrivacyPolicy": "cobalt's privacy policy is simple: no data about you is ever collected or stored. zero, zilch, nada, nothing.\nwhat you download is solely your business, not mine or anyone else's.\n\nif your download requires rendering, then data about requested content is encrypted and temporarily stored in server's RAM. it's necessary for this feature to function.\n\nencrypted data is stored for 90 seconds and then permanently removed.\n\nstored data is only possible to decrypt with unique encryption keys from your download link. furthermore, the official cobalt codebase doesn't provide a way to read temporarily stored data outside of processing functions.\n\nyou can check cobalt's source code yourself and see that everything is as stated.",
- "ErrorYTUnavailable": "this youtube video is unavailable. it could be age or region restricted. try another one!",
- "ErrorYTTryOtherCodec": "i couldn't find anything to download with your settings. try another codec or quality in settings!",
- "SettingsCodecSubtitle": "youtube codec",
- "SettingsCodecDescription": "h264: best support across apps/platforms, average detail level. max quality is 1080p.\nav1: best quality, small file size, most detail. supports 8k & HDR.\nvp9: same quality as av1, but file is x2 bigger. supports 4k & HDR.\n\npick h264 if you want best compatibility.\npick av1 if you want best quality and efficiency.",
- "SettingsAudioDub": "youtube audio track",
- "ShareURL": "share",
- "ErrorTweetUnavailable": "couldn't find anything about this tweet. this could be because its visibility is limited. try another one!",
- "PopupCloseDone": "done",
- "Accessibility": "accessibility",
- "SettingsReduceTransparency": "reduce transparency",
- "SettingsDisableAnimations": "disable animations",
- "FeatureErrorGeneric": "your browser doesn't allow or support this feature. check if there are any updates available and try again!",
- "ClipboardErrorFirefox": "you're using firefox where all clipboard reading functionality is disabled.\n\nyou can fix this by following steps listed here!\n\n...or you can paste the link manually instead.",
- "ClipboardErrorNoPermission": "cobalt can't access the most recent item in your clipboard without your permission.\n\nif you don't want to give access, just paste the link manually instead.\n\nif you do, go to site settings and enable the clipboard permission.",
- "SupportSelfTroubleshooting": "experiencing issues? try one of these first:",
- "AccessibilityGoBack": "go back and close the popup",
- "CollapseKeyboard": "keyboard shortcuts",
- "KeyboardShortcutsIntro": "use cobalt even faster with keyboard shortcuts:",
- "KeyboardShortcutQuickPaste": "paste the link",
- "KeyboardShortcutClear": "clear link input area",
- "KeyboardShortcutClosePopup": "close all popups",
- "CollapseLegal": "terms and ethics",
- "FairUse": "cobalt is a web tool that makes it easier to download content from the internet and takes zero liability. processing servers work like limited proxies, so no media content is ever cached or stored.\n\nyou (end user) are responsible for what you download, how you use and distribute that content. please be mindful when using content of others and always credit original creators.\n\nwhen used in education purposes (lecture, homework, etc) please attach the source link.\n\nfair use and credits benefit everyone.",
- "SettingsDisableMetadata": "don't add metadata",
- "NewDomainWelcomeTitle": "hey there!",
- "NewDomainWelcome": "cobalt is moving! same features, same owner, simply a more rememberable domain. and still no ads.\n\ncobalt.tools is the new main domain, aka where you are now. make sure to update your bookmarks and reinstall the web app!",
- "DataTransferSuccess": "btw, your settings have been transferred automatically :)",
- "DataTransferError": "something went wrong when transferring your preferences. you'll have to open settings and configure cobalt by hand.",
- "SupportNotAffiliated": "cobalt is not affiliated with any services listed above.",
- "SponsoredBy": "sponsored by",
- "FilenameTitle": "file name style",
- "FilenamePatternClassic": "classic",
- "FilenamePatternPretty": "pretty",
- "FilenamePatternBasic": "basic",
- "FilenamePatternNerdy": "nerdy",
- "FilenameDescription": "classic: default cobalt file name pattern.\nbasic: title and basic info in brackets.\npretty: title and info in brackets.\nnerdy: title and all info in brackets.\n\nsome services don’t support rich file names and always use the classic style.",
- "Preview": "preview",
- "FilenamePreviewVideoTitle": "Video Title",
- "FilenamePreviewAudioTitle": "Audio Title",
- "FilenamePreviewAudioAuthor": "Audio Author",
- "StatusPage": "service status page",
- "TroubleshootingGuide": "self-troubleshooting guide",
- "DonateImageDescription": "cat sleeping on a laptop keyboard and typing letters repeatedly",
- "SettingsTwitterGif": "convert gifs to .gif",
- "SettingsTwitterGifDescription": "converting looping videos to .gif reduces quality and majorly increases file size. if you want best efficiency, keep this setting off.",
- "ErrorTweetProtected": "this tweet is from a private account, so i can't see it. try another one!",
- "ErrorTweetNSFW": "this tweet contains sensitive content, so i can't see it. try another one!",
- "PrivateAnalytics": "private analytics",
- "SettingsDisableAnalytics": "opt out of private analytics",
- "SettingsAnalyticsExplanation": "enable if you don't want to be included in anonymous traffic stats. read more about this in about > privacy policy (tl;dr: nothing about you is ever stored or tracked, no cookies are used).",
- "AnalyticsDescription": "cobalt uses a self-hosted plausible instance to get an approximate number of how many people use it.\n\nplausible is fully compliant with GDPR, CCPA and PECR, doesn't use cookies, and never stores any identifiable info, not even your ip address.\n\nall data is aggregated and never personalized. nothing about what you download is ever saved anywhere. it's used just for anonymous traffic stats, nothing more.\n\nplausible is fully open source, just like cobalt, and if you want to learn more about it, you can do so here. if you wish to opt out of traffic stats, you can do it in settings > other.",
- "SettingsTikTokH265": "prefer h265",
- "SettingsTikTokH265Description": "download 1080p videos from tiktok in h265/hevc format when available.",
- "SettingsYoutubeDub": "use browser language",
- "SettingsYoutubeDubDescription": "uses your browser's default language for youtube dubbed audio tracks. works even if cobalt ui isn't translated to your language.",
- "UpdateIstream": "better service support and ux"
- }
-}
diff --git a/src/localization/languages/ru.json b/src/localization/languages/ru.json
deleted file mode 100644
index 9ba1643b..00000000
--- a/src/localization/languages/ru.json
+++ /dev/null
@@ -1,162 +0,0 @@
-{
- "name": "русский",
- "substrings": {
- "ContactLink": "глянь статус серверов или напиши о проблеме на github (можно на русском)"
- },
- "strings": {
- "AppTitleCobalt": "кобальт",
- "LinkInput": "вставь ссылку сюда",
- "AboutSummary": "кобальт - твой друг при скачивании контента из соцсетей и других сервисов. никакой рекламы, трекеров и прочего мусора. вставляешь ссылку и получаешь файл. всё. ничего лишнего.",
- "EmbedBriefDescription": "сохраняй то, что любишь. без рекламы, трекеров и лишней мороки.",
- "MadeWithLove": "сделано с любовью <3",
- "AccessibilityInputArea": "зона вставки ссылки",
- "AccessibilityOpenAbout": "открыть окно с инфой",
- "AccessibilityDownloadButton": "кнопка скачивания",
- "AccessibilityOpenSettings": "открыть настройки",
- "AccessibilityOpenDonate": "сделать пожертвование",
- "TitlePopupAbout": "что за кобальт?",
- "TitlePopupSettings": "настройки",
- "TitlePopupChangelog": "что нового?",
- "TitlePopupDonate": "поддержи кобальт",
- "TitlePopupDownload": "как сохранить?",
- "ErrorSomethingWentWrong": "что-то пошло совсем не так и у меня не получилось ничего для тебя достать. попробуй ещё раз, но если так и не получится, {ContactLink}.",
- "ErrorUnsupported": "с твоей ссылкой что-то не так или же этот сервис ещё не поддерживается. может быть, ты вставил не ту ссылку?",
- "ErrorBrokenLink": "{s} поддерживается, но с твоей ссылкой что-то не так. может быть, ты её не полностью скопировал?",
- "ErrorNoLink": "пока что я не умею угадывать, что ты хочешь скачать. дай мне, пожалуйста, ссылку :(",
- "ErrorPageRenderFail": "если ты видишь этот текст, значит что-то не так с рендером страницы. пожалуйста, {ContactLink}. также приложи домен, на котором присутсвует эта ошибка, и хэш коммита ({s}). спасибо :)",
- "ErrorRateLimit": "ты делаешь слишком много запросов. попробуй ещё раз через минуту!",
- "ErrorCouldntFetch": "у меня не получилось ничего найти по этой ссылке. убедись, что она работает, и попробуй ещё раз. некоторый контент может быть залочен на регион.",
- "ErrorLengthLimit": "я не могу обрабатывать видео длиннее чем {s} минут(ы), так что скачай что-нибудь покороче!",
- "ErrorBadFetch": "произошла какая-то ошибка при получении данных по твоей ссылке. убедись, что она работает, и попробуй ещё раз.",
- "ErrorNoInternet": "не получилось подключиться к серверу. проверь подключение к интернету и попробуй ещё раз!",
- "ErrorCantConnectToServiceAPI": "у меня не получилось подключиться к серверу этого сервиса. возможно он лежит, или же кобальт заблокировали. попробуй ещё раз, но если так и не получится, {ContactLink}.",
- "ErrorEmptyDownload": "я не нашёл того, что могу скачать. попробуй другую ссылку!",
- "ErrorLiveVideo": "я пока что не умею заглядывать в будущее, поэтому дождись окончания прямого эфира, и потом уже скачивай видео!",
- "SettingsAppearanceSubtitle": "внешний вид",
- "SettingsThemeSubtitle": "тема",
- "SettingsFormatSubtitle": "формат",
- "SettingsQualitySubtitle": "качество",
- "SettingsThemeAuto": "авто",
- "SettingsThemeLight": "светлый",
- "SettingsThemeDark": "тёмный",
- "SettingsKeepDownloadButton": "всегда показывать >>",
- "AccessibilityKeepDownloadButton": "всегда показывать кнопку скачивания на экране",
- "SettingsEnableDownloadPopup": "выбор метода скачивания",
- "AccessibilityEnableDownloadPopup": "спрашивать, что делать с загрузками",
- "SettingsQualityDescription": "если выбранное качество недоступно, то выбирается ближайшее к нему.",
- "NoScriptMessage": "кобальт использует javascript для обработки ссылок и интерактивного интерфейса. ты должен разрешить использование javascript, чтобы пользоваться сайтом. тут нет никаких зловредных скриптов, обещаю.",
- "DownloadPopupDescriptionIOS": "как сохранить в фото:\n1. добавь этот сценарий siri: save to photos.\n2. нажми \"поделиться\" выше этого текста.\n3. выбери \"save to photos\" в открывшемся окне.\n\nкак сохранить в файлы:\n1. добавь этот сценарий siri: save to files.\n2. нажми \"поделиться\" выше этого текста.\n3. выбери \"save to files\" в открывшемся окне.\n4. выбери папку для сохранения файла и нажми \"открыть\".\n\nоба сценария работают только вместе с веб-приложением кобальта.",
- "DownloadPopupDescription": "кнопка скачивания открывает новое окно с файлом. ты можешь отключить выбор метода скачивания файла в настройках.",
- "ClickToCopy": "нажми, чтобы скопировать",
- "Download": "скачать",
- "CopyURL": "скопировать",
- "AboutTab": "о сайте",
- "ChangelogTab": "изменения",
- "DonationsTab": "донаты",
- "SettingsVideoTab": "видео",
- "SettingsAudioTab": "аудио",
- "SettingsOtherTab": "другое",
- "ChangelogLastMajor": "текущая версия и коммит (на английском)",
- "AccessibilityModeToggle": "переключить режим скачивания",
- "DonateLinksDescription": "это лучший способ отправить донат, если ты хочешь, чтобы я получил его лично.",
- "SettingsAudioFormatBest": "лучший",
- "SettingsAudioFormatDescription": "когда выбран \"лучший\", ты получишь аудио без каких-либо изменений. такое, какое оно есть на стороне сервиса. если же выбрано что-то другое, то аудио будет немного сжато.",
- "Keyphrase": "сохраняй то, что любишь",
- "ErrorPopupCloseButton": "ясно",
- "ErrorLengthAudioConvert": "я не могу конвертировать аудио дольше чем {s} минут(ы). выбери \"лучший\" формат, чтобы обойти ограничения.",
- "SettingsAudioFullTikTok": "полное аудио",
- "SettingsAudioFullTikTokDescription": "скачивает оригинальный звук, использованный в видео, без каких-либо изменений от автора поста.",
- "ErrorCantGetID": "у меня не получилось достать инфу по этой короткой ссылке. попробуй полную ссылку, а если так и не получится, то {ContactLink}.",
- "ErrorNoVideosInTweet": "я не смог найти никакого медиа контента в этом твите. попробуй другой!",
- "ImagePickerTitle": "выбери картинки для скачивания",
- "ImagePickerDownloadAudio": "скачать звук",
- "ImagePickerExplanationPC": "нажми правой кнопкой мыши на картинку, чтобы её сохранить.",
- "ImagePickerExplanationPhone": "зажми и удерживай картинку, чтобы её сохранить.",
- "ErrorNoUrlReturned": "я не получил ссылку для скачивания от сервера. такого происходить не должно. попробуй ещё раз, а если не поможет, то {ContactLink}.",
- "ErrorUnknownStatus": "сервер ответил мне чем-то непонятным. такого происходить не должно. попробуй ещё раз, а если не поможет, то {ContactLink}.",
- "PasteFromClipboard": "вставить",
- "ChangelogOlder": "предыдущие версии (тоже на английском)",
- "ChangelogPressToExpand": "раскрыть",
- "Miscellaneous": "разное",
- "ModeToggleAuto": "авто",
- "ModeToggleAudio": "аудио",
- "MediaPickerTitle": "выбери, что сохранить",
- "MediaPickerExplanationPC": "кликни то, что хочешь скачать. также можно скачать правой кнопки мыши.",
- "MediaPickerExplanationPhone": "нажми, или нажми и удерживай, чтобы скачать.",
- "MediaPickerExplanationPhoneIOS": "нажми и удерживай, затем скрой превью и выбери \"загрузить файл по ссылке\", чтобы скачать.",
- "TwitterSpaceWasntRecorded": "мне нечего скачать, так как этот twitter space не был записан. попробуй другой!",
- "ErrorCantProcess": "я не смог обработать твой запрос :(\nты можешь попробовать ещё раз, но если не поможет, то {ContactLink}.",
- "ChangelogPressToHide": "скрыть",
- "Donate": "донаты",
- "DonateSub": "ты можешь помочь!",
- "DonateExplanation": "кобальт не пихает рекламу тебе в лицо и не продаёт твои личные данные, а значит работает совершенно бесплатно для всех. но разработка и поддержка медиа сервиса, которым пользуются более 750 тысяч людей, обходится довольно затратно.\n\nесли кобальт тебе помог и ты хочешь, чтобы он продолжал расти и развиваться, то это можно сделать через донаты!\n\nтвой донат поможет всем, кто пользуется кобальтом: преподавателям, студентам, музыкантам, художникам, контент-мейкерам и многим-многим другим!\n\nв прошлом донаты помогли кобальту:\n*; повысить стабильность и аптайм почти до 100%.\n*; ускорить ВСЕ загрузки, особенно наиболее тяжёлые.\n*; открыть api для бесплатного использования.\n*; выдержать несколько огромных наплывов пользователей без перебоев.\n*; добавить ресурсоемкие фичи (например конвертацию в gif).\n*; продолжать улучшать нашу инфраструктуру.\n*; радовать разработчиков.\n\nкаждый донат невероятно ценится и помогает кобальту развиваться!\n\nесли ты не можешь отправить донат, то поделись кобальтом с другом! мы нигде не размещаем рекламу, поэтому кобальт распространяется из уст в уста.\nподелиться - самый простой способ помочь достичь цели лучшего интернета для всех.",
- "DonateVia": "открыть",
- "SettingsVideoMute": "убрать аудио",
- "SettingsVideoMuteExplanation": "убирает звук при загрузке видео, но только когда это возможно.",
- "ErrorSoundCloudNoClientId": "мне не удалось достать временный токен, который необходим для скачивания аудио из soundcloud. попробуй ещё раз, но если так и не получится, {ContactLink}.",
- "CollapseServices": "что поддерживается?",
- "CollapseSupport": "поддержка и исходный код",
- "CollapsePrivacy": "политика конфиденциальности",
- "ServicesNote": "этот список далеко не финальный и постоянно пополняется, заглядывай сюда почаще!",
- "FollowSupport": "подписывайся на соц.сети кобальта для новостей и поддержки:",
- "SourceCode": "шарься в исходнике, пиши о проблемах, или же форкай репозиторий:",
- "PrivacyPolicy": "политика конфиденциальности кобальта довольно проста: никакие данные о тебе никогда не собираются и не хранятся. нуль, ноль, нада, ничего.\nто, что ты скачиваешь, - твоё личное дело, а не чьё-либо ещё.\n\nесли твоей загрузке требуется рендер, то зашифрованные данные о ней временно хранятся в ОЗУ сервера. это необходимо для работы данной функции.\n\nзашифрованные данные хранятся в течение 90 секунд и затем безвозвратно удаляются.\n\ncохранённые данные можно расшифровать только с помощью уникальных ключей шифрования из твоей ссылки на скачивание. кроме того, официальная кодовая база кобальта не предусматривает возможности чтения эти данные вне функций обработки.\n\nты всегда можешь посмотреть исходный код кобальта и убедиться, что всё так, как заявлено.",
- "ErrorYTUnavailable": "это видео недоступно. возможно оно ограничено по доступу или региону. попробуй другое!",
- "ErrorYTTryOtherCodec": "я не нашёл того, что мог бы скачать с твоими настройками. попробуй другой кодек или качество в настройках!",
- "SettingsCodecSubtitle": "кодек для youtube видео",
- "SettingsCodecDescription": "h264: лучшая совместимость, средний уровень детализированности. максимальное качество - 1080p.\nav1: лучшее качество, маленький размер файла, наибольшее количество деталей. поддерживает 8k и HDR.\nvp9: такая же детализированность, как и у av1, но файл в 2 раза больше. поддерживает 4k и HDR.\n\nвыбирай h264, если тебе нужна наилучшая совместимость.\nвыбирай av1, если ты хочешь лучшее качество и эффективность.",
- "SettingsAudioDub": "звуковая дорожка для youtube видео",
- "ShareURL": "поделиться",
- "ErrorTweetUnavailable": "не смог найти что-либо об этом твите. возможно его видимость ограничена. попробуй другой!",
- "PopupCloseDone": "готово",
- "Accessibility": "общедоступность",
- "SettingsReduceTransparency": "уменьшить прозрачность",
- "SettingsDisableAnimations": "убрать анимации",
- "FeatureErrorGeneric": "твой браузер не разрешает или не поддерживает эту функцию. проверь наличие обновлений и попробуй ещё раз!",
- "ClipboardErrorFirefox": "ты используешь firefox в котором все функции чтения из буфера обмена отключены по умолчанию.\n\nно это можно исправить следуя шагам, описанным здесь\n\n...или же ты можешь просто вставить ссылку вручную.",
- "ClipboardErrorNoPermission": "кобальт не может прочитать последний элемент в буфере обмена без твоего разрешения.\n\nесли ты не хочешь давать доступ, просто вставь ссылку вручную.\n\nну а если хочешь, то открой настройки сайта и разреши доступ на чтение буфера обмена.",
- "SupportSelfTroubleshooting": "возникли проблемы? попробуй сначала что-то из этого:",
- "AccessibilityGoBack": "вернуться назад и закрыть окно",
- "CollapseKeyboard": "горячие клавиши",
- "KeyboardShortcutsIntro": "пользуйся кобальтом ещё быстрее с горячими клавишами:",
- "KeyboardShortcutQuickPaste": "вставить ссылку",
- "KeyboardShortcutClear": "очистить зону вставки ссылки",
- "KeyboardShortcutClosePopup": "закрыть все окна",
- "CollapseLegal": "принципы и этика",
- "FairUse": "кобальт - это веб инструмент для облегчения скачивания контента из интернета. сервера обработки работают как ограниченные прокси, так что ничего никогда не сохраняется или кэшируется.\n\nкобальт не несёт никакой ответственности, только ты (конечный пользователь) несёшь ответственность за то, что скачиваешь, как используешь и распространяешь скачанный контент. будь сознателен при использовании чужого контента и всегда указывай авторов!\n\nприкладывай ссылку на источник при использовании в образовательных целях (лекции, домашние задания и т.п.)\n\nчестное использование и указание авторства выгодно всем.",
- "SettingsDisableMetadata": "не добавлять метаданные",
- "NewDomainWelcomeTitle": "привет!",
- "NewDomainWelcome": "кобальт переезжает! те же функции, тот же владелец, просто более запоминающийся домен. по-прежнему без рекламы.\n\ncobalt.tools - новый основной домен, т.е. где ты сейчас находишься. не забудь обновить закладки и переустановить веб-приложение!",
- "DataTransferSuccess": "кстати, твои настройки были перенесены автоматически :)",
- "DataTransferError": "при переносе настроек что-то пошло не так. придётся зайти в настройки и настроить кобальт вручную.",
- "SupportNotAffiliated": "кобальт не аффилирован ни с одним из перечисленных выше сервисов.",
- "SupportMetaNoticeRU": "деятельность meta platforms inc. (владелец instagram) запрещена на территории россии.",
- "SponsoredBy": "спонсируется",
- "FilenameTitle": "стиль названий файлов",
- "FilenamePatternClassic": "классический",
- "FilenamePatternPretty": "красивый",
- "FilenamePatternBasic": "простой",
- "FilenamePatternNerdy": "полный",
- "FilenameDescription": "классический: стандартный стиль названия файлов кобальта.\nпростой: название и основная инфа в скобках.\nкрасивый: название и инфа в скобках.\nполный: название и вся инфа в скобках.\n\nнекоторые сервисы не поддерживают красивые имена файлов и всегда используют классический стиль.",
- "Preview": "превью",
- "FilenamePreviewVideoTitle": "Название Видео",
- "FilenamePreviewAudioTitle": "Название Аудио",
- "FilenamePreviewAudioAuthor": "Автор Аудио",
- "StatusPage": "статус серверов",
- "TroubleshootingGuide": "гайд по устранению проблем",
- "DonateImageDescription": "кошка спит на клавиатуре ноутбука и многократно печатает буквы",
- "SettingsTwitterGif": "конвертировать гифки в .gif",
- "SettingsTwitterGifDescription": "конвертирование зацикленного видео в .gif снижает качество и значительно увеличивает размер файла. если важна максимальная эффективность, то не используй эту функцию.",
- "ErrorTweetProtected": "этот твит из закрытого аккаунта, поэтому я не могу его увидеть. попробуй другой!",
- "ErrorTweetNSFW": "этот твит содержит деликатный контент, поэтому я не могу его увидеть. попробуй другой!",
- "PrivateAnalytics": "приватная аналитика",
- "SettingsDisableAnalytics": "отключить приватную аналитику",
- "SettingsAnalyticsExplanation": "включи, если не хочешь быть частью анонимной статистики трафика. подробнее об этом можно прочитать в политике конфиденциальности (tl;dr: ничего о тебе или твоих действиях не хранится и не отслеживается, даже куки нет).",
- "AnalyticsDescription": "кобальт использует собственный инстанс plausible чтобы иметь приблизительное представление о том, сколько людей им пользуются.\n\nplausible полностью соответствует GDPR, CCPA и PECR, не использует куки и никогда не хранит никакой идентифицируемой информации, даже ip-адрес.\n\nвсе данные агрегируются и никогда не персонализируются. ничего о том, что ты скачиваешь, никогда не сохраняется. это просто анонимная статистика трафика, ничего больше.\n\nplausible также как и кобальт имеет открытый исходный код, и, если ты хочешь узнать о нём больше, то это можно сделать здесь. а если же ты хочешь исключить себя из статистики, то это можно сделать в настройках > другое.",
- "SettingsTikTokH265": "предпочитать h265",
- "SettingsTikTokH265Description": "скачивает видео с tiktok в 1080p и h265/hevc, когда это возможно.",
- "SettingsYoutubeDub": "использовать язык браузера",
- "SettingsYoutubeDubDescription": "использует главный язык браузера для аудиодорожек на youtube. работает даже если кобальт не переведён в твой язык.",
- "UpdateIstream": "быстрые загрузки и приятный интерфейс"
- }
-}
diff --git a/src/localization/manager.js b/src/localization/manager.js
deleted file mode 100644
index 2344241b..00000000
--- a/src/localization/manager.js
+++ /dev/null
@@ -1,51 +0,0 @@
-import * as fs from "fs";
-import { links, repo } from "../modules/config.js";
-import { loadJSON } from "../modules/sub/loadFromFs.js";
-
-const locPath = './src/localization/languages';
-
-let loc = {}
-let languages = [];
-
-export async function loadLoc() {
- const files = await fs.promises.readdir(locPath).catch(() => []);
- files.forEach(file => {
- loc[file.split('.')[0]] = loadJSON(`${locPath}/${file}`);
- languages.push(file.split('.')[0])
- });
-}
-
-export function replaceBase(s) {
- return s
- .replace(/\n/g, ' ')
- .replace(/{saveToGalleryShortcut}/g, links.saveToGalleryShortcut)
- .replace(/{saveToFilesShortcut}/g, links.saveToFilesShortcut)
- .replace(/{repo}/g, repo)
- .replace(/{statusPage}/g, links.statusPage)
- .replace(/\*;/g, "•");
-}
-export function replaceAll(lang, str, string, replacement) {
- let s = replaceBase(str[string])
- if (replacement) s = s.replace(/{s}/g, replacement);
- if (s.match('{')) {
- Object.keys(loc[lang]["substrings"]).forEach(sub => {
- s = replaceBase(s.replace(`{${sub}}`, loc[lang]["substrings"][sub]))
- });
- }
- return s
-}
-export default function(lang, string, replacement) {
- try {
- if (!Object.keys(loc).includes(lang)) lang = 'en';
- let str = loc[lang]["strings"];
- if (str && str[string]) {
- return replaceAll(lang, str, string, replacement)
- } else {
- str = loc["en"]["strings"];
- return replaceAll(lang, str, string, replacement)
- }
- } catch (e) {
- return `!!${string}!!`
- }
-}
-export const languageList = languages;
diff --git a/src/modules/api.js b/src/modules/api.js
deleted file mode 100644
index c3549bb3..00000000
--- a/src/modules/api.js
+++ /dev/null
@@ -1,33 +0,0 @@
-import { services } from "./config.js";
-
-import { apiJSON } from "./sub/utils.js";
-import { errorUnsupported } from "./sub/errors.js";
-import loc from "../localization/manager.js";
-import match from "./processing/match.js";
-import { getHostIfValid } from "./processing/url.js";
-
-export async function getJSON(url, lang, obj) {
- try {
- const host = getHostIfValid(url);
-
- if (!host || !services[host].enabled) {
- return apiJSON(0, { t: errorUnsupported(lang) });
- }
-
- let patternMatch;
- for (const pattern of services[host].patterns) {
- patternMatch = pattern.match(
- url.pathname.substring(1) + url.search
- );
- if (patternMatch) break;
- }
-
- if (!patternMatch) {
- return apiJSON(0, { t: errorUnsupported(lang) });
- }
-
- return await match(host, patternMatch, url, lang, obj)
- } catch (e) {
- return apiJSON(0, { t: loc(lang, 'ErrorSomethingWentWrong') })
- }
-}
diff --git a/src/modules/build.js b/src/modules/build.js
deleted file mode 100644
index a4c4aa6b..00000000
--- a/src/modules/build.js
+++ /dev/null
@@ -1,41 +0,0 @@
-import * as esbuild from "esbuild";
-import * as fs from "fs";
-import { loadLoc, languageList } from "../localization/manager.js";
-import { cleanHTML } from "./sub/utils.js";
-
-import page from "./pageRender/page.js";
-
-export async function buildFront(commitHash, branch) {
- try {
- // preload localization files
- await loadLoc();
-
- // build html
- if (!fs.existsSync('./build/')){
- fs.mkdirSync('./build/');
- }
- // get rid of old build path
- if (fs.existsSync('./min')) {
- fs.rmSync('./min', { recursive: true, force: true });
- }
- for (let i in languageList) {
- i = languageList[i];
- let params = {
- "hash": commitHash,
- "lang": i,
- "branch": branch
- }
- fs.writeFileSync(`./build/${i}.html`, cleanHTML(page(params)));
- }
- // build js & css
- await esbuild.build({
- entryPoints: ['src/front/cobalt.js', 'src/front/cobalt.css'],
- outdir: 'build/min/',
- minify: true,
- loader: { '.js': 'js', '.css': 'css', },
- charset: 'utf8'
- })
- } catch {
- return;
- }
-}
diff --git a/src/modules/buildStatic.js b/src/modules/buildStatic.js
deleted file mode 100644
index d3ed909f..00000000
--- a/src/modules/buildStatic.js
+++ /dev/null
@@ -1,7 +0,0 @@
-import { buildFront } from "./build.js";
-import { getCurrentBranch, shortCommit } from "./sub/currentCommit.js";
-
-const commitHash = shortCommit();
-const branch = getCurrentBranch();
-
-await buildFront(commitHash, branch);
diff --git a/src/modules/changelog/changelog.json b/src/modules/changelog/changelog.json
deleted file mode 100644
index 94569ec0..00000000
--- a/src/modules/changelog/changelog.json
+++ /dev/null
@@ -1,297 +0,0 @@
-{
- "current": {
- "version": "7.13",
- "date": "May 5, 2024",
- "title": "better ux, improvements for youtube, twitter, tiktok, instagram, and more!",
- "banner": {
- "file": "meowthbusinessman.webp",
- "alt": "photo of a businessman holding hands together (merkel-raute pose) with meowth plush head.",
- "width": 1440,
- "height": 960
- },
- "content": "long time no see! well, actually, you've been using the latest version for some time now. we've moved to a rolling release scheme, allowing for speedy update rollouts :)\n\nsince 7.11, there has been a ton of changes. here are the most notable of them:\n*; youtube downloads are now faster and more reliable than ever.\n*; all posts from twitter are now downloadable, including sensitive ones.\n*; you now can download tiktok videos in 1080p h265! just enable h265 support in settings > video.\n*; added support for sharing links directly to the cobalt web app on android.\n*; added 240p and 144p quality options to the quality picker in settings (for some reason, many of you wanted this).\n*; pasting a link with additional text around it will now work; cobalt will extract the link for you (works only via the paste button).\n*; added anonymous traffic analytics by plausible. we're using a selfhosted instance and don't collect any identifiable information about you. you can learn more in about > privacy policy. you can also opt out of anonymous analytics in settings > other.\n\nservice support improvements:\n*; implemented internal streams functionality, allowing for more fine-grained file streaming and therefore proper youtube support.\n*; added fallback to m4a if opus isn't available for youtube.\n*; added a total of 7 ways to get instagram post info, including mobile api, embed, and graphql api. absolute torture.\n*; added support for reddit user posts.\n*; updated the way tiktok downloads are handled for better reliability and 1080p support.\n*; added tiktok author's username to filename.\n*; added support for rutube shorts and yappy videos.\n*; added support for m.soundcloud.com links.\n*; added support for new post and reel links from instagram.\n*; added support for photo twitter links, only used for gifs.\n*; added support for m.bilibili.com links.\n*; added support for new type of vimeo links.\n*; added support for ddinstagram.com links.\n*; updated youtube codec info in settings to display the fact that av1 is a better choice now.\n*; updated best audio picking for tiktok and soundcloud.\n*; changed the youtube client to web, since android client no longer works.\n*; removed the vimeo download type switcher, as it should've always been automatic instead.\n*; removed an ability to enable the tiktok watermark, as it no longer includes the author's username.\n\nui & ux improvements:\n*; youtube audio dub switcher is now a toggle with a much easier to understand description.\n*; meowbalt now sticks out on the left side of download popup on desktop.\n*; updated \"made with love\" text to include the research & dev team behind cobalt, imput.\n*; fixed grammar of russian localization.\n*; rounded corners are now correctly rendered across all browsers.\n*; various minor improvements, including smaller button padding.\n*; removed the notification (red dot) functionality as the most recent changelog is already always on screen.\n*; removed settings migration from the old domain.\n\nother changes:\n*; various docs updates in github repo, making sure they're functional across branches and forks.\n*; major codebase cleanup.\n\nthank you for using cobalt, and thank you for being one of our 900k friends! i hope you like this update as much as we liked making it.\n\nwe're committed to keeping cobalt the best way to save what you love without ads or invasion of your privacy. there's a ton of cool stuff to come soon; stay tuned and have an amazing rest of your day <3\n\nif you want to help our goal of a better internet for everyone, just share cobalt with a friend!\n\n(original photo of a man in a suit by benzoix on freepik)"
- },
- "history": [{
- "version": "7.11",
- "date": "March 6, 2024",
- "title": "cache encryption, meowbalt, dailymotion, bilibili, and much more!",
- "banner": {
- "file": "meowth7eleven.webp",
- "alt": "meowth plush in front of 7-eleven store",
- "width": 850,
- "height": 640
- },
- "content": "cobalt may not have as many groceries as 7-eleven, but it sure does have lots of big changes in this update!\n\n*; all cached stream info is now encrypted and can only be decrypted with a link you get from cobalt.\n*; new popup style featuring meowbalt, cobalt's speedy mascot. you will see him more often from now on!\n*; added support for dailymotion (including short links).\n*; added support for bilibili.tv, fixed support for bilibili.com, and added support for all related short links.\n*; added support for unlisted vimeo links.\n*; added support for tumblr audio and revamped the entire module.\n*; added support for embed ok.ru links.\n\nwe also updated the privacy policy to reflect the addition of data encryption, go check it out.\n\nfor people with iphones:\n*; clearer ios saving tutorial.\n*; added \"save to files\" ios shortcut.\n*; updated save to photos shortcut.\n\nmake sure to save both shortcuts and read the updated tutorial!\n\nfor people who host a cobalt instance:\n*; updated all environment variables TO_BE_LIKE_THIS. time to update your configs! for now cobalt is backwards compatible with old variable names, but it won't last forever.\n*; added a list of all environment variables and their descriptions to run-an-instance doc.\n*; updated cookie file example with more services and improved examples.\n*; updated docker compose example with better explanations and up-to-date env variable samples.\n*; updated some packages to get rid of all unnecessary messages in console.\n\nwant to host an instance? learn how to do it here.\n\nfrontend changes:\n*; removed migration popup.\n*; corners across ui are even more round now.\n*; bottom glass bkg in popups is no longer rounded on top right.\n*; small popup no longer stretches like gum, it's fixed in size on desktop.\n*; small popup animation no longer lags on mobile.\n*; better ui scaling across resolutions.\n*; updated donation text.\n\nthank you for using cobalt, all 750k of you. hope you like this update as much as we enjoyed making it :D"
- }, {
- "version": "7.9",
- "date": "January 17, 2024",
- "title": "twitter gifs, pinterest, ok.ru, and more!",
- "banner": {
- "file": "meowthball.webp",
- "alt": "meowth rolling on a big catnip ball",
- "width": 478,
- "height": 350
- },
- "content": "yes, you read that right. cobalt now lets you convert any twitter gif to an actual .gif file! (finally)\njust go to settings and enable this feature :)\n\nservice improvements:\n*; added an option to convert gifs from twitter into actual .gif format. files will be bigger and lower quality, but maybe you want that.\n*; pinterest support has been completely redone, now all videos (and even pin.it links) are supported.\n*; added support for ok.ru in case you're a russian grandma.\n*; now processing all reddit links (including old.reddit.com).\n*; instagram live vods are now supported.\n*; fixed a rare vimeo bug related to 1440p videos.\n\nother improvements:\n*; ui fade in animation is no longer present if you've disabled animations.\n*; all images now have alt descriptions.\n*; cobalt html is now biblically correct and follows the html spec.\n*; lots of cleaning up.\n\npatches since 7.8:\n*; shift+key shortcuts are now ignored if url bar is focused.\n*; longer soundcloud links are now supported, also catching more tiktok-related errors.\n*; removed mastodon from support links as that account is no longer active.\n*; added ability to download a specific video from multi media tweets and support for /mediaViewer links.\n*; fixed modal blurriness in chromium.\n*; minor html changes (road to biblically correct one).\n\nlots of long-awaited updates (especially twitter gifs), hope you enjoy them and have a great day :D"
- }, {
- "version": "7.8",
- "date": "December 25, 2023",
- "title": "new years clean up! bug fixes and fresh look for the home page",
- "banner": {
- "file": "catroomba.webp",
- "alt": "a cat riding a roomba vacuum",
- "width": 300,
- "height": 168
- },
- "content": "merry christmas and happy new year! this update fixes several (very annoying) bugs to help you enjoy your holidays better.\n\nyou might have already noticed, but we've refreshed the home page on desktop and mobile! less space wasted, more pleasant to look at. let us know if you like it or not :D\n\nservice improvements:\n*; #264 anything that includes a period in the url should be possible to download (including instagram stories).\n*; #73 soundcloud: falling back to mp3 instead of refusing to download the song at all.\n*; #275 youtube: query parameters are parsed and handled correctly, all links should be supported, no matter where v query is located.\n*; tlds are parsed and validated correctly (e.g. \"pinterest.co.uk\" works now).\n*; fixvx.com links are now supported.\n\ninterface improvements:\n*; cleaner and more consistent home page layout.\n*; cleaned up support section in \"about\". also includes a link to the status page.\n\ninternal improvements:\n*; urls, subdomains, and tlds are properly validated.\n*; minor clean up.\n\nchanges since 7.7:\n*; made terms and ethics more descriptive.\n*; fix only affected twitter videos.\n*; fixed quick ⌘+V pasting on mac.\n*; now catching even more youtube-related errors.\n\nthis might not seem like a lot, but even smaller changes make a difference!\n\nenjoy this update and the rest of your day :D"
- }, {
- "version": "7.7",
- "date": "December 2, 2023",
- "title": "bugfixes and better downloads!",
- "banner": {
- "file": "meowthpolishegg.webp",
- "alt": "meowth polishing a togepi egg",
- "width": 640,
- "height": 480
- },
- "content": "this update fixes various issues with supported services. no new features yet, but twitter fix is surely something good to have in the meantime!\n\nservice improvements:\n*; broken twitter videos are now automatically fixed by cobalt.\n*; all vimeo videos and audios should now be possible to download.\n*; vimeo: fixed short resolution displayed in \"basic\" and \"pretty\" filename styles.\n\ninterface improvements:\n*; streamables are now easier to save on ios.\n\ninternal improvements:\n*; port env variable is now not strictly necessary for cobalt to run.\n*; minor clean up.\n\nchanges since 7.6:\n*; fix for an issue related to youtube dubs.\n*; fixed a memory leak related to live renders.\n*; handling all errors related to twitter downloads.\n*; fixed support for reddit links in various languages.\n*; added rich filenames support for twitch clips.\n*; updated support and donation lists.\n\nstay tuned for future updates and have a great day :D"
- }, {
- "version": "7.6",
- "date": "October 15, 2023",
- "title": "customizable file names, instagram stories, and first cobalt sponsor!",
- "banner": {
- "file": "meowthcenter.webp",
- "alt": "meowth plush in a datacenter wearing a hardhat, wielding a hammer",
- "width": 851,
- "height": 640
- },
- "content": "as many have (very) often requested, cobalt now lets you pick between several file name format styles!\ngo to settings > other and change it to whichever you like! there's a preview of each style, so you know how exactly files are gonna look like.\n\nif you liked file names the way they were before, don't worry: classic style is still the default :)\n\non a different but not any less important note: cobalt is now sponsored by royalehosting.net!\noverall service performance and stability is gonna be better, but also more content will be possible to download thanks to geniuine server locations. and yes, still no ads or trackers.\n\nthis update also includes a bunch of other changes, check them out:\n\nservice improvements:\n*; added support for instagram stories thanks to #194.\n*; fixed reddit support thanks to #221.\n*; added support for rich file names for youtube, vimeo, soundcloud, rutube, and vk.\n*; numbers and emoji no longer disappear from file name and metadata.\n*; mute and audio dub file name tags don't appear together anymore.\n*; youtube: dub file name tag doesn't appear anymore if audio track is default.\n\ninterface improvements:\n*; added a list of sponsors to about tab. if you host an instance, it's disabled by default, but can be enabled with showSponsors env variable.\n*; about button now opens about tab when no new changelog is available.\n*; fixed download button thickness on ios.\n\nyou now can reach out to cobalt via email for support! it's located in the about tab along with other socials, such as discord.\n\ni hope you enjoy this long-awaited update and have a blissful day :D"
- }, {
- "version": "7.5",
- "date": "September 16, 2023",
- "title": "support for twitch clips and rutube!",
- "banner": {
- "file": "twitchupdate.webp",
- "alt": "meowth plush staring into the camera, laptop with generic purple service in the background",
- "width": 851,
- "height": 640
- },
- "content": "hey! this update (finally) adds support for twitch clips and rutube, among other smaller changes.\n\nservice improvements:\n*; added support for twitch clips. no vods, they're unnecessary. just clip whatever you want to download!\n*; added support for rutube in case you ever wanted to download something russian.\n\ninterface improvements:\n*; added a note about cobalt not being affiliated with any supported services.\n*; added a note about meta (the company) in russian.\n*; better russian localization. will keep improving it to make it sound not so robotic over time.\n\nother improvements:\n*; all official servers are now using the docker package. and so should you!\n*; moved the load balancer to poland. requests should be slightly faster now.\n*; minor codebase clean up.\n\nif you're confused about the new domain, read the older changelog! just scroll lower and press \"expand\".\n\ni hope you find this update useful and have a wonderful day :)\n\nbtw, cobalt has a pretty active community server on discord. go to about > support & source code to join!"
- }, {
- "version": "7.4",
- "date": "September 9, 2023",
- "title": "new domain, what's coming in future, bug fixes, and more!",
- "banner": {
- "file": "newdomain.webp",
- "alt": "text: new domain, same cobalt",
- "width": 960,
- "height": 540
- },
- "content": "cobalt is finally moving to its own domain! many of you have been anticipating this, and many kept forgetting the link due to how cryptic it was.\n\nwell, worry no more - cobalt.tools is here.\n\nif you haven't yet, open co.wukko.me to transfer your settings here! no additional action from you is required. just open the old link and cobalt will do everything for you :)\n\nmake sure to update your bookmarks and reinstall the web app!\n\nhere's what domain change means:\n*; still no ads, same owner, same features, same reliability. just a way more rememberable link (it's literally two words).\n*; cobalt.tools makes it clear that cobalt is a tool and that it's \"cobalt\", not \"wukko\".\n*; i can host various versions of cobalt on subdomains without links looking awkward.\n*; i can host cobalt-related websites without polluting my personal domain's dns (such as crowdin).\n*; i stand by same privacy policies (and in fact am using the same exact server as before).\n\nthe domain change is required for the future of cobalt.\n\nhere's what's coming soon:\n*; support for many top-requested sites, such as (but not limited to) twitch and niconico.\n*; education version of cobalt, as often requested by students and educators.\n*; major localization system upgrade, allowing for simpler community contributions.\n*; region-specific versions with 100% translations and tweaks.\n*; native clients for desktop and mobile (not sure about this one, i'm no superman).\n*; ...and more!\n\nnow, here's what's new in 7.4:\n*; tabs in popups now scroll to top on tab bar tap.\n*; padding across web app was tuned.\n*; (obviously) a migration agent. soon will be used for importing and exporting settings.\n*; some minor clean ups in codebase.\n\nif you want to help cobalt achieve goals listed above, consider donating! donations are the only way i can keep cobalt ad-less, powerful, (basically) limitless, and also 100% free.\n\nin fact, donations have helped me grow cobalt more than i've ever anticipated. just imagine how much better it will be in a year.\n\ngo to donations down below to find ways to donate!\n\nthank you for reading through all of this. i hope you enjoy this update and have a great day :D"
- }, {
- "version": "7.2 & 7.3",
- "date": "September 6, 2023",
- "title": "extended video length limit, metadata toggle, ui improvements, and more!",
- "banner": {
- "file": "meowthsnap.webp",
- "alt": "cartoon meowth pointing paw dramatically and saying something",
- "width": 500,
- "height": 280
- },
- "content": "this update gives cobalt a sharp look in chromium browsers and makes it even more useful than before. check out the full changelog below!\n\nservice improvements:\n*; increased video length limit from 3 hours to 5 hours. feel free to download lectures you need :)\n*; you can now disable file metadata in settings.\n*; fixed a bug which previously caused some downloads to end up being 0 bytes.\n\nui improvements:\n*; fixed clickable area for urgent notice (text on top).\n*; fixed blurry header in chrome.\n*; fixed blurry tab bar in chrome.\n*; fixed blurry switches in chrome.\n*; fixed weirdly rounded corners in popups.\n*; fixed 1px gap on edges of various elements in popup in chrome.\n*; fixed overscrolling in other settings tab on ios.\n*; fixed unexpected button highlight effect on phones.\n*; removed outdated fixes for tiny screens.\n\nother improvements:\n*; cobalt web & api start faster than before, additional preparation functions aren't unexpectedly run anymore.\n*; cobalt is now available as a docker package. check it out on github.\n\nthank you for being here. i hope you have a great day :D"
- }, {
- "version": "7.1",
- "date": "August 20, 2023",
- "title": "instagram, streamable, video metadata, and more!",
- "banner": {
- "file": "meowthproductions.webp",
- "alt": "meowth roaring in a fancy circle, à la MGM studios intro",
- "width": 640,
- "height": 358
- },
- "content": "service improvements:\n*; extended instagram support: high quality photos, videos, reels. everything should work without any issues, enjoy! :)\n*; added support for streamable.com (thanks to #179)\n*; added video metadata to youtube videos.\n*; fixed vk video downloads.\n*; vxtwitter links are now supported.\n*; fixed support for youtube audio dubs.\n\nui improvements:\n*; fixed picker popup: it's now scrollable in all cases and clickable areas don't overlap each other.\n\nbackend improvements:\n*; cobalt will now let you know if something goes wrong during video download instead of nuking the stream.\n*; added support for cookies (thanks to #177)\n*; replaced got with undici (thanks to #182). downloads should be slightly faster and clean of garbage in headers.\n\ninternal improvements:\n*; moved host overrides into its own module.\n*; minor clean ups.\n\neven more cool stuff is coming in future updates! thank you for using cobalt :D"
- }, {
- "version": "7.0",
- "date": "August 15, 2023",
- "title": "biggest ui refresh yet!",
- "banner": {
- "file": "meowthcooking.webp",
- "alt": "meowth handling orders in a restaurant",
- "width": 640,
- "height": 360
- },
- "content": "hey! this update is huge and mostly aimed to refresh the ui, but there are also some other nice fixes/additions. read below for more info :)\n\ntl;dr:\n*; entirety of web app has been refreshed. it's more prettier and optimized than ever, both on phone and desktop.\n*; if you're on ios, try adding cobalt to home screen! it'll look and act like a native app.\n*; all soundcloud links are now supported and audio quality is higher than before.\n*; all x (previously twitter) links are now supported and work properly.\n*; newer reddit videos are downloadable now.\n*; added some sort of eula, list of keyboard shortcuts, updated privacy policy for more clarity. check it all in refreshed about tab!\n*; cobalt now lets you know if your browser doesn't support clipboard pasting and helps you fix it.\n\naccessibility notice:\nthis update includes animations and transparency, if you'd like to disable any or all of them, head to settings > other > accessibility.\n\n[full changelog]\n\nservice improvements:\n*; fixed unexpected 502 errors when downloading newer reddit videos.\n*; newer reddit videos (with audio) are downloadable now.\n*; upgraded soundcloud downloads to use higher audio quality than before.\n*; all soundcloud links are now supported.\n*; added support for x.com urls.\n*; changed twitter api once again. now everything works, again.\n\nweb improvements:\n*; all-new matte glass aesthetic, applied to revamped popup headers, tab selectors, and also small popups.\n*; rounded corners everywhere! cobalt is now safe for everyone who can't handle sharp objects.\n*; paddings everywhere are smaller, more content fits on the screen at once.\n*; optimized installed web app to look and act like a native app, especially on ios.\n*; added update release dates to changelogs.\n*; cobalt now lets you know if your browser doesn't support clipboard api and helps you fix it.\n*; refreshed all popups: less padding, more content.\n*; completely remade error and download popups, they're consistent with the rest of refreshed design.\n*; refreshed the look of entire changelog tab: separated title and version/commit, made title bigger, evened out all paddings.\n*; replaced close button with back button, moved it to left.\n*; added interaction animations.\n*; added more keyboard shorcuts.\n*; added a list of keyboard shortcuts to about tab.\n*; added eula to about tab. check it out.\n*; added more accessibility options, put them all into one category. you can disable animations and transparency if you want to.\n*; added a link to self-troubleshooting guide to about tab.\n*; renamed 2160p and 4320p to 4k and 8k respectfully for better clarity.\n*; popups now work without any weird workarounds, especially on mobile. they're clean and nice.\n*; home screen now also works without any weird workarounds. it is also clean and nice.\n*; optimized css of almost all ui elements. should be even more consistent across platforms now.\n*; added ability to translate \"cobalt\" more in-depth localization. for example, in russian \"cobalt\" is now \"кобальт\", that's the style i'll be going with from now on.\n*; updated many localization strings for more clarity.\n*; removed ability to change the app name dynamically in all locations. cobalt is a sustained app name.\n*; updated donation and privacy policy texts for more clarity in both english and russian.\n*; home screen now smoothly fades in instead of popping in.\n*; proper banner loading. no more jumping text!\n*; proper banner error handling. if banner wasn't loaded, it'll simply go grey instead of disappearing.\n*; links are no longer italic and are instead underlined.\n*; collapsible lists now have corresponding emoji.\n*; donate button is now highlighted with magenta instead of white.\n*; proper dropdown arrow.\n*; removed 6.0 api fallback.\n*; fixed celebrations emoji. again.\n*; cleaned up all related frontend modules, especially page.js.\n*; urgent notice is now a js element, not a static piece of text. can be updated easily.\n\napi improvements:\n*; now catching all json api related errors.\n*; moved on demand blocks to web server, now changelog can be updated independently from preferred api server.\n*; now sending standard rate limiting headers.\n*; better readability in source.\n\nother improvements:\n*; renamed docker-compose.yml.example to docker-compose.example.yml for linting in code editors.\n*; added a wiki with wip troubleshooting guide on github. more guides are coming soon!\n\nthat's a ton of changes! i really hope you like this update as much as i do.\n\nif you experience any issues, feel free to contact me on any platform listed in about tab! i'd love to hear back from you.\n\nthank you for sticking with me and cobalt, i hope you have THE best day :D"
- }, {
- "version": "6.2",
- "date": "June 27 2023",
- "title": "all network issues have been fixed!",
- "banner": {
- "file": "meowthhammer.webp",
- "alt": "meowth plush holding a hammer in real life",
- "width": 1280,
- "height": 827
- },
- "content": "hey! there have been some hiccups in cobalt's stability lately, i was going through finals while trying to scale up the infrastructure, and that didn't really work out, lol.\nBUT i'm happy to announce that i've optimized all nodes! there should no longer be any networking issues.\n\nenjoy stable experience while i work in background to make cobalt even better :)\n\nhere's what's new in this update:\n*; better button contrast in both themes. \n*; button highlight in light theme now actually looks like a highlight.\n*; removed ip gate for streamables and updated privacy policy to reflect this change.\n*; streamable links now last for 20 seconds instead of 2 minutes.\n*; cleaned up stream verification algorithm. now the same function doesn't run 4 times in a row.\n*; removed deprecated way of hosting a cobalt instance.\n\nthank you for sticking with cobalt, and i hope you have a great day :D\n\nbanner photo is by @halftroller on twitter, thank you so much!"
- }, {
- "version": "6.0",
- "date": "June 7, 2023",
- "title": "better reliability, new infrastructure, pinterest support, and way more!",
- "banner": {
- "file": "catswitchboxes.webp",
- "alt": "a cat climbing into two empty boxes of asahi beer",
- "width": 600,
- "height": 314
- },
- "content": "hey! long time no see, hopefully over 40 changes will make up for it :)\n\ncobalt now has an official community discord server. you can go there for news, support, or just to chat. go check it out!\n\ntl;dr\n*; new infra, new hosting structure, new main instance api url. developers, get it here.\n*; added support for pinterest, vine archive, tumblr audio, youtube vr videos.\n*; better web app performance and look.\n*; better stability thanks to load balancing.\n*; (hopefully) no more random video/audio download drops.\n\nservice improvements:\n*; added support for pinterest videos and stories (pr by @Snazzah).\n*; added support for tumblr audio. sorry, tumblr.\n*; added support for youtube vr videos. please note that they're in youtube's proprietary ratio.\n*; added support for vine archive.\n*; added support for ancient vk videos in 240p.\n*; fixed an issue related to muted video downloads from tumblr.\n*; moved to twitter v2 api.\n*; soundcloud share links are now processed without errors.\n\nui improvements:\n*; lazy image loading. should significantly speed up the page load.\n*; fixed checkbox width on mobile devices.\n*; addition of a temporary urgent notice.\n*; added hover border to all buttons.\n*; less annoying donation button highlight.\n*; more consistent color scheme.\n*; added link to a discord server into about popup.\n*; remember celebratory emoji changes? they've been fixed, and are now dynamically loaded!\n*; changelog history now lets you try to load it again if first attempt failed for whatever reason.\n*; padding (everywhere) has been slightly reduced to fit in more content and be consistent across ui.\n*; added more info to the \"how to save\" popup for ios devices.\n*; crypto wallet press-to-copy buttons now look like buttons.\n*; improved ui layout for smallest screens (iphone 5, 5s, se, etc).\n*; removed partial translations for sake of clarity and consistency.\n\ninternal improvements:\n*; separated web and api servers. they're now completely independent and therefore more stress-resistant.\n*; added a dedicated script for building the web app if you don't want to reload the frontend server.\n*; web app building improvements.\n*; async localization preloading.\n*; consistent server start time reporting.\n*; dynamic stream and ip hashing salt generation.\n\ninfrastructure improvements:\n*; load balancing: your api requests are now sent to the least busy server. yes, there are now several of them with more to come in the future.\n*; when possible, server in closest region is used instead of a far-away one. this should help with download speeds.\n*; currently there are multiple servers in europe. i will let you know when (and if) i manage to get an american one.\n\nupdates for developers and instance hosters:\n*; server info api endpoint: you can now check up on the api server of choice. it reports all the basic info you may need. check the api docs for more info.\n*; api names: each and every api instance should have a distinctive name. this will be useful in the future :)\n*; added docker compose sample config.\n*; updated and more granular setup script.\n*; better api scalability and faster server start up thanks to web and api separation.\n*; added ability to specify ffmpeg threads. simply add ffmpegThreads to your environment variables!\n\ni'm still in awe from how popular cobalt has become. there are now over 200k of unique users monthly, and that number only keeps growing. i even had to come up with something to accommodate for larger traffic, it's absolutely insane.\n\nlove you all, have a great day :D"
- }, {
- "version": "5.4",
- "title": "instagram support, docker, and more!",
- "banner": {
- "file": "catphonestand.webp",
- "alt": "a cat holding a phone under its chin while a person plays clash of clans on it",
- "width": 451,
- "height": 272
- },
- "content": "something many of you've been waiting for is finally here! try it out and let me know what you think :)\n\ntl;dr:\n*; added experimental instagram support! download any reels or videos you like, and make sure to report any issues you encounter. yes, you can convert either to audio.\n*; fixed support for on.soundcloud links.\n*; added share button to \"how to save?\" popup.\n*; added docker support.\n\nservice improvements:\n*; added experimental support for videos from instagram. currently only reels and post videos are downloadable, but i'm looking into ways to save high resolution photos too. if you experience any issues, please report them on either of support platforms.\n*; fixed support for on.soundcloud share links. should work just as well as other versions!\n*; fixed an issue that made some youtube videos impossible to download.\n\ninterface improvements:\n*; new css-only checkmark! yes, i can't stop tinkering with it because slight flashing on svg load annoyed me. now it loads instantly (and also looks slightly better).\n*; fixed copy animation.\n*; minor localization improvements.\n*; fixed the embed logo that i broke somewhere in between 5.3 and 5.4.\n\ninternal improvements:\n*; now using nanoid for live render stream ids.\n*; added support for docker. it's kind of clumsy because of how i get .git folder inside the container, but if you know how to do it better, feel free to make a pr.\n*; cobalt now checks only for existence of environment variables, not exactly the .env file.\n*; changed the way user ip address is retrieved for instances using cloudflare.\n*; added ability to disable cors, both to setup script and environment variables.\n\ni can't believe how diverse and widespread cobalt has become. it's used in all fields: music production, education, content creation, and even game development. thank you. this is absolutely nuts.\nif you don't mind sharing, please tell me about your use case. i'd really love to hear how you use cobalt and how i could make it even more useful for you."
- }, {
- "version": "5.3",
- "title": "better looks, better feel",
- "banner": {
- "file": "cattired.webp",
- "alt": "a cat laying on a sofa face down, wiggling its tail",
- "width": 640,
- "height": 286
- },
- "content": "this update isn't as big as previous ones, but it still greatly enhances the cobalt experience.\n\nhere's what's up:\n*; new mode switcher! elegant and 100% clear. should no longer cause any confusion. let me know if you like it better this way :D\n*; wide paste button on mobile is back, but now it's even closer to your finger.\n*; removed the weird grey chin on changelog banners.\n*; removed left-handed layout toggle since it is no longer needed.\n*; fixed input area display in chromium 112+.\n*; centered the main action box.\n*; cleaned up css of main action box to get rid of tricks and ensure correct display on all devices.\n*; fixed a bug that'd cause notifications dots to disappear when an unrelated checkbox was checked.\n\nhopefully from now on i'll focus on adding support for more services.\nthank you for using cobalt. stay cool :)"
- }, {
- "version": "5.2",
- "title": "fastest one in the game",
- "banner": {
- "file": "catspeed.webp",
- "alt": "a cat running very fast in an exercise wheel",
- "width": 640,
- "height": 356
- },
- "content": "hey, notice anything different? well, at very least the page loaded way faster! this update includes many improvements and fixes, but also some new features.\n\ntl;dr:\n*; twitter retweet links are now supported.\n*; all vimeo videos should now be possible to download.\n*; you now can download audio from vimeo.\n*; it's now possible to pick between preferred vimeo download method in settings.\n*; fixed issues related to tiktok, twitter, twitter spaces, and vimeo downloads.\n*; overall cobalt performance should be MUCH better.\n\nservice improvements:\n*; added support for twitter retweet links. now all kinds of tweet links are supported.\n*; fixed the issue related to periods in tiktok usernames (#96).\n*; fixed twitter spaces downloads.\n*; added support for audio downloads from vimeo.\n*; added ability to choose between \"progressive\" and \"dash\" vimeo downloads. go to settings > video to pick your preference.\n*; fixed the issue related to vimeo quality picking.\n*; fixed the issue when vimeo module wouldn't show appropriate errors and instead would fallback to default ones.\n*; improved audio only downloads for some edge cases.\n*; (hopefully) better youtube reliability.\n*; temporarily disabled douyin support due to api endpoint cut off.\n\ninterface improvements:\n*; merged clipboard and mode switcher rows into one for mobile view.\n*; added left-handed layout toggle for those who prefer to have the clipboard button on left.\n*; new custom-made clipboard icon. now it clearly indicates what it does.\n*; improved english and russian localization. both are way more direct and less bloaty.\n*; frontend page is now rendered once and is cached on disk instead of being rendered every time someone requests a page. this greatly improves page loading speeds and further reduces strain put on the server.\n*; frontend page is now minimized just like js and css files. this should minimize traffic wasted on loading the page, along with minor loading speed improvement.\n*; added proper checkbox icon for better clarity.\n*; checkboxes are now stretched edge-to-edge on phone to be easier to manage for right-handed people.\n*; removed button hover highlights on phones.\n*; fixed button press animations for safari on ios.\n*; fixed text selection on ios. previously you could select text or images anywhere, but now they're selectable in limited places, just like on other platforms.\n*; frontend platform is now marked in settings: p is for pc; m is for mobile; i is for ios. this is done for possible future debugging and issue-solving.\n*; better error messaging.\n\ninternal improvements:\n*; better rate limiting, there should be way less cases of accidental limits.\n*; added support for m3u8 playlists. this will be useful for future additions, and is currently used by vimeo module.\n*; added support for \"chop\" stream format for vimeo downloads.\n*; fixed vk user id extraction. i assumed the - in url was a separator, but it's actually a part of id.\n*; completely reworked the vimeo module. it's much cleaner and better performant now.\n*; minor clean ups across the board.\n\nnot really related to this update, but thank you for 50k monthly users! i really appreciate that you're still here, because that means i'm doing some things right :D"
- }, {
- "version": "5.1",
- "title": "the evil has been defeated",
- "banner": {
- "file": "happymeowth.webp",
- "alt": "meowth jumping up into the sky very excitedly",
- "width": 500,
- "height": 330
- },
- "content": "hey, ever wanted to download a youtube video without a hassle? cobalt is here to help. this update fixes all issues related to youtube downloads.\nnot only that, but it also introduces features never before seen in a downloader, such as youtube dub downloads! read below to see what's up :)\n\ntl;dr:\n*; audio in youtube videos FINALLY no longer gets cut off.\n*; you now can pick any video resolution you want (from 360p to 8k) and any possible youtube video codec (h264/av1/vp9).\n*; you now can download youtube videos with dubs in your native language. just check settings > audio.\n*; youtube processing has been vastly sped up.\n\nok, now onto the nerdy part of changelog. this update is pretty huge and includes improvements across the board.\n\nservice improvements:\n*; all youtube functionality has been reworked. cobalt now relies on innertube apis, not web scraping.\n*; random audio cut off issue has been fixed, let me know if it ever occurs again. (closes #62, #66, #75, #88).\n*; added support for youtube dubs. currently it's using your browser's default language when enabled, but i have plans on making a picker. i'll ask people on twitter and mastodon if this feature is needed, and add a picker in next updates.\n*; instead of adding more quality presets, i added granular quality options. pick whatever you like, from 360p up to 4320p (for all services, not just youtube).\n*; replaced a format picker with codec picker for youtube. you can pick h264, av1, or vp9. all of them should work as expected (closes #88).\n*; youtube audio files are now properly matched to corresponding video files.\n*; it's now always possible to download pristine h264 720p/360p videos from youtube. these videos will work ANYWHERE, so they're default for mobile.\n*; youtube requests are no longer permanently cached, ram usage should drop even further.\n*; youtube video and audio file names now include codec and dub language when applicable.\n*; max video and audio duration limits have been bumped up to 3 hours.\n*; general performance of entire youtube download process has been greatly improved.\n*; vk module has been reworked to be more compact and not make use of outdated technique of quality picking. should also be way more reliable.\n\ninternal improvements:\n*; cleaned up services config, all constants have been moved directly to modules for quicker access.\n*; matching module has been slightly cleaned up.\n\ninterface improvements:\n*; many descriptions and error messages have been slightly tuned to be less wordy.\n*; unnecessary title duplications in settings have been merged into one.\n*; added more clarity to quality and codec descriptions.\n\nif you use cobalt api, please note that you have to update your creation to support new features.\n\nthis is the second batch of 5.x improvements, there's way more to come. thank you for being here, i really appreciate your support.\n\nif you want to thank me (the developer), there's a nice tab under this changelog that has \"donations\" text on it. anything helps me continue developing and hosting the friendliest media downloader :D"
- }, {
- "version": "5.0",
- "title": "it's all about attention to detail!",
- "banner": {
- "file": "valentines.webp",
- "alt": "relaxed meowth with sakura petals falling in front of them",
- "width": 489,
- "height": 374
- },
- "content": "happy valentine's day! i have an update for you, as a gift :D\n\ntl;dr: added support for reddit gifs, fixed douyin downloads, fixed vimeo quality picking, revamped entirety of codebase, and many other fixes.\n\nhere's more info:\n\nthis update is mostly about cleaning up and polishing the codebase, but it also has some new features. here's what's up:\n\nservice-related improvements:\n*; you now can download gifs from reddit!\n*; attempting to download a video from douyin no longer throws an error (bytedance changed the api endpoint, yet again).\n*; fixed quality picking for vimeo downloads.\n*; fixed length limit check in vimeo module.\n*; fixed support for \"user view\" vk clips links.\n*; various twitter errors are now displayed correctly instead of falling back to the default error.\n*; state of all services is now tested on each commit.\n\nui improvements:\n*; cobalt social links no longer disappear if you have an aggressive ad blocking extension installed.\n*; various localization improvements for both english and russian.\n*; changed some service aliases to display full list of supported downloads.\n*; added current branch information to version text (in settings).\n*; fixed typos in older changelogs.\n\ninternal improvements:\n*; everything has been sanitized, improved, and refactored. code is now much easier to read and maintain.\n*; rewrote and/or optimized all modules that were messy or inefficient.\n*; all git interaction functions now store info in cache instead of fetching it every time the function is called.\n*; added a test script that checks functionality of all supported services.\n*; updated deepsource config. checks are more accurate now.\n*; requests from internet explorer are now dropped entirely instead of redirecting people stuck in 90s to a proper browser download page. this was done to avoid (my) personal bias towards browsers.\n\ni put a ton of effort into this version, and i hope you like it as much as i do.\n\nthank you for using cobalt. there's so much more to come :)"
- }, {
- "version": "4.8",
- "title": "prettier than ever",
- "banner": {
- "file": "catmakeup.webp",
- "alt": "a cat being brushed with a powder makeup brush",
- "width": 394,
- "height": 266
- },
- "content": "this version brings many visual improvements and a completely revamped \"about\" tab.\n\nwhat's new in \"about\" tab:\n*; all information is now split into collapsible sections, making it easier to navigate.\n*; added privacy policy to further prove that none of your data is collected.\n*; added emoji to the page title to make it look consistent with other pages.\n*; added mastodon account handle and link.\n*; there are now short notes at the end of each section.\n*; other changes that are too small to describe. just go check it out!\n\nvisual improvements:\n*; less wasted space: paddings and margins have been reduced and optimized for usability, consistency, and overall beauty.\n*; all links are now in italic. it's much easier to tell them apart from regular highlights.\n*; error popup no longer looks broken and out of place.\n*; download popup now has a proper close button, not something from 2.x era.\n*; emoji are no longer selectable or draggable.\n*; better scalability: desktop layout for home screen is shown if device viewport is wide enough to fit in three action buttons.\n*; page shouldn't look broken on phones in landscape mode (i still highly recommend using cobalt in portrait mode).\n*; removed bulletpoint padding. it was unnecessary.\n*; updated some service names.\n\nas always, you can suggest features or report bugs on any platform listed in the \"support\" section of about tab.\n\nthank you for using cobalt. i hope you have a good day :)"
- }, {
- "version": "4.7",
- "title": "we're better together! thank you for bug reports.",
- "banner": {
- "file": "bettertogether.webp",
- "alt": "various different pokémon jumping in happiness",
- "width": 640,
- "height": 358
- },
- "content": "this update includes a bunch of improvements, many of which were made thanks to the community :D\n\nservice-related improvements:\n*; private soundcloud links are now supported (#68);\n*; tiktok usernames with dots in them no longer confuse cobalt (#71);\n*; .ogg files no longer wrongfully include a video channel (#67);\n*; fixed an issue that caused cobalt to freak out when user attempted to download an audio from audio-only service with \"mute video\" option enabled.\n\nui improvements:\n*; popup padding has been evened out. popups are now able to fit in more information on scroll, especially on mobile;\n*; all buttons are now of even size and are displayed without any padding issues across all modern browsers and devices;\n*; checkbox is no longer crippled on ios;\n*; many explanation texts have been simplified to get rid of unnecessary bloat (no bullshit, remember?);\n*; moved tiktok section in video settings higher due to higher priority;\n*; fixed unexpectedly displayed scrollbars on switch rows in firefox.\n\nstability improvements:\n*; ffmpeg process now should end upon finishing the render;\n*; ffmpeg should also quit when download is abruptly cut off;\n*; fixed a memory leak that was caused by misconfigured stream information caching (#63).\n\ninternal improvements:\n*; requested streams are now stored in cache for 2 minutes instead of 1000 hours (yes, 1000 hours, i fucked up);\n*; cached data is now reused if user requests same content within 2 minutes;\n*; page render module is now even cleaner than before;\n*; proper support for bullet-points in loc strings.\n\nyou can suggest features or report bugs on github or twitter. both work just fine, use whichever you're more comfortable with.\n\nthank you for using cobalt, and thank you for reading this changelog.\n\nyou're amazing, keep it up :)"
- }, {
- "version": "4.6",
- "title": "mute videos and proper soundcloud support",
- "banner": {
- "file": "shutup.webp",
- "alt": "a cat yawning, with a crossed out loudspeaker icon next to it",
- "width": 1024,
- "height": 665
- },
- "content": "i've been longing to implement both of these things, and here they finally are.\n\nservice-related improvements:\n*; you now can download videos with no audio! simply enable the \"mute audio\" option in settings > audio.\n*; soundcloud module has been updated, and downloads should no longer break after some time.\nvisual improvements:\n*; moved some things around in settings popup, and added separators where separation is needed.\n*; updated some texts in english and russian.\n*; version and commit hash have been joined together, now they're a single unit.\ninternal improvements:\n*; updated api documentation to include isAudioMuted.\n*; simplified the startup message.\n*; created render elements for separator and explanation due to high duplication of them in the page.\n*; fully deprecated GET method for API requests.\n*; fixed some code quirks.\nhere's how soundcloud downloads got fixed:\n\npreviously, client_id was (stupidly) hardcoded. that means cobalt wasn't able to fetch song data if soundcloud web app got updated.\nnow, cobalt tries to find the up-to-date client_id, caches it in memory, and checks if web app version has changed to update the id accordingly. you can see this change for yourself on github."
- }, {
- "version": "4.5",
- "title": "better, faster, stronger, stable",
- "banner": {
- "file": "meowthstrong.webp",
- "alt": "meowth stretching",
- "width": 500,
- "height": 280
- },
- "content": "your favorite social media downloader just got even better! this update includes a ton of improvements and fixes.\n\nin fact, there are so many changes, i had to split them in sections.\n\nservice-related improvements:\n*; vimeo module has been revamped, all sorts of videos should now be supported.\n*; vimeo audio downloads! you now can download audios from more recent videos.\n*; cobalt now supports all sorts of tumblr links. (even those scary ones from the mobile app)\n*; vk clips support has been fixed. they rolled back the separation of videos and clips, so i had to do the same.\n*; youtube videos with community warnings should now be possible to download.\nuser interface improvements:\n*; list of supported services is now MUCH easier to read.\n*; banners in changelog history should no longer overlap each other.\n*; bullet points! they have a bit of extra padding, so it makes them stand out of the rest of text.\ninternal improvements:\n*; cobalt will now match the link to regex when using ?u= query for autopasting it into input area.\n*; better rate limiting: limiting now is done per minute, not per 20 minutes. this ensures less waiting and less attack area for request spammers.\n*; moved to my own fork of ytdl-core, cause main project seems to have been abandoned. go check it out on github or npm!\n*; ALL user inputs are now properly sanitized on the server. that includes variables for POST api method, too.\n*; \"got\" package has been (mostly) replaced by native fetch api. this should greatly reduce ram usage.\n*; all unnecessary duplications of module imports have been gotten rid of. no more error passing strings from inside of service modules. you don't make mistakes only if you don't do anything, right?\n*; other code optimizations. there's less clutter overall.\nhuge update, right? seems like everything's fixed now?\n\nnope, one issue still persists: sometimes youtube server drops packets for an audio file while cobalt's rendering the video for you. this results in abrupt cuts of audio. if you want to help solving this issue, please feel free to do it on github!\n\nthank you for reading this, and thank you for sticking with cobalt and me."
- }, {
- "version": "4.4",
- "title": "over 1 million monthly requests. thank you.",
- "banner": {
- "file": "onemillionr.webp",
- "alt": "cobalt logo and a confetti emoji",
- "width": 1441,
- "height": 1441
- },
- "content": "this is a huge milestone for me, i cannot express enough how grateful i am for each and every one of you.\nthank you for using cobalt, and thank you for showing that people love the web that's friendly and bullshit-free. i'm hoping to never disappoint you in the future and keep up the good work.\n\nthank you <3\n\nif you want to thank ME, check out the renovated donations tab, which now is also linked alongside bottom action buttons."
- }, {
- "version": "4.3.2",
- "title": "twitter improvements & changelog overhaul",
- "content": "- you can download explicit content from twitter.\n- direct video links from twitter are properly supported (video/1, video/2, etc.).\n- changelog history got support for banners.\n- changelog categories are not messy anymore.\n- cobalt version in changelogs is now highlighted.\n- changelog history got separators to make text easier to read.\n- changelog history can be collapsed after loading.\n- download button takes less time to change back to pressable state.\n\nif you're a developer and would like to play around with cobalt's api, then read more about it in older changelogs below!"
- }, {
- "version": "4.3",
- "title": "developers, developers, developers, developers",
- "banner": {
- "file": "developers.webp",
- "alt": "steve ballmer going \"developers, developers, developers\"",
- "width": 640,
- "height": 360
- },
- "content": "this update features a TON of improvements.\n\ndevelopers, you now can rely on cobalt for getting content from social media. the api has been revamped and documentation is now available. you can read more about API changes down below. go crazy, and have fun :D\n\nif you're not a developer, here's a list of changes that you probably care about:\n- rate limit is now approximately 8 times bigger. no more waiting, even if you want to download entirety of your tiktok \"for you\" page.\n- some updates will now have expressive banners, just like this one.\n- fixed what was causing an error when a youtube video had no description.\n- mp4 format button text should now be displayed properly, no matter if you touched the switcher or not.\n\nnext, the star of this update — improved api!\n- main endpoint now uses POST method instead of GET.\n- internal variables for preferences have been updated to be consistent and easier to understand.\n- ip address is now hashed right upon request, not somewhere deep inside the code.\n- global stream salt variable is no longer unnecessarily passed over a billion functions.\n- url and picker keys are now separate in the json response.\n- cobalt web app now correctly processes responses with \"success\" status.\n\nif you currently have a siri shortcut or some other script that uses the GET method, make sure to update it soon. this method is deprecated, limited, and will be removed entirely in coming updates.\n\nif you ever make something using cobalt's api, make sure to mention @justusecobalt on twitter, i would absolutely love to see what you made."
- }, {
- "version": "4.2",
- "title": "optimized quality picking and 8k video support",
- "content": "- this update fixes quality picking that was accidentally broken in 4.0 update.\n- you now can download videos in 8k from youtube. why would you that? no idea. but i'm more than happy to give you this option.\n- default video quality for downloads from pc is now 1440p, and 720p for phones.\n- default video format is now mp4 for everyone.\n- default audio format is now mp3 for everyone.\n\nyou can always change new defaults back to whatever you prefer in settings.\n\nother changes:\n- added more clarity to quality picker description.\n- youtube video codecs are now right in the picker.\n- setup script is now easier to understand."
- }, {
- "version": "4.1",
- "title": "better tiktok image downloads",
- "content": "here's what's up:\n- tiktok images are saved as .jpeg instead of .webp (finally, i know).\n- added support for image downloads from douyin.\n- fixed tiktok audio downloads from the image picker.\n- emoji in about button now changes on special occasions. be it halloween or christmas, cobalt will change just a tiny bit to fit in :D\n\nif you're not caught up with new stuff in cobalt 4.x yet, check out the previous changelog down below. there's a ton of stuff to like."
- }, {
- "version": "4.0",
- "title": "better and faster than ever",
- "content": "this update has a ton of improvements and new features.\n\nchanges you probably care about:\n- cobalt now has support for recorded twitter spaces! download the previous conversation no matter how long it was.\n- download speeds from youtube are at least 10 times better now. you're welcome.\n- both video and audio length limits have been extended to 2 hours.\n- audio downloads from youtube, youtube music, twitter spaces, and soundcloud now have metadata! most often it's just title and artist, but when cobalt is able to get more info, it adds that metadata too.\n- tiktok downloads have been fixed, yet again, and if they ever break in the future, cobalt will fall back to downloading a less annoyingly watermarked video.\n- soundcloud downloads have been fixed, too.\n\nless notable changes:\n- currently experimenting with using mp3 as default audio format. if you set something other than mp3 before, it'll be set to mp3. you can always change it back in settings. let me know what you think about this.\n- \"download audio\" button from image picker no longer stays on the screen after popup was closed.\n- clipboard button now shows up depending on your browser's support for it.\n- you can no longer manually hide the clipboard button, 'cause it's unnecessary.\n- small internal improvements such as separation of changelog version and title.\n- fair bit of internal clean up.\n\nif you want to help me implement covers for downloaded audios, you can do it on github."
- }, {
- "version": "3.7",
- "title": "support for multi media tweets is here!",
- "content": "cobalt now lets you save any of the videos or gifs in a tweet. even if there are many of them.\n\nsimply paste a link like you'd usually do and cobalt will ask what exactly you want to save.\n\nFIREFOX USERS: if you have strict tracking protection on, you might wanna turn it off for cobalt, or else twitter video previews won't load. firefox filters out twitter image cdn as if it was a tracker, which it's not. it's a false-positive.\n\nhowever, you can leave it on if you're fine with blank squares and video numbers. i have thought of that in prior, you're welcome.\n\nother changes:\n- repurposed ex tiktok-only image picker to be dynamic and adapt depending on content to pick. that's exactly how twitter multi media downloads work.\n- cobalt is now properly viewable on phones with tiny screens, such as first gen iphone se.\n- scrollbars now should be visible only where they're needed.\n- brought back proper twitter api, because other one doesn't have multi media stuff (at least yet).\n- cleaned up some internal files, including main frontend js file.\n- reorganized some files in project directory, now you won't get lost when contributing or just looking through cobalt's code."
- }, {
- "version": "3.6.2 + 3.6.3",
- "title": "less disturbance",
- "content": "changelog popup no longer annoys you after a major update! this action has been replaced with a notification dot. if you see a red dot, then there's something new.\n\nyour old setting that disabled the changelog popup now applies to notifications.\n\nnew users will see a notification dot instead of an about popup, too. this was mostly done to prevent complications if your browser is set up to clean local storage when you close it.\n\nother changes:\n- popups are now a bit wider, just so more content fits at once.\n- better interface scaling.\n- code is a bit cleaner now.\n- changed twitter api endpoint. there should no longer be any rate limits."
- }, {
- "version": "3.6",
- "title": "improvements all around!",
- "content": "- download mode switcher is moving places, it's now right next to link input area.\n- smart mode has been renamed to auto mode, because this name is easier to understand.\n- all spacings in ui have been evened out. no more eye strain.\n- added support for twitter /video/1 links\n- clipboard button exception has been redone to prepare for adoption of readtext clipboard api in firefox.\n- cobalt is now using different tiktok api endpoint, because previous one got killed, just like the one before.\n- \"other\" settings tab has been cleaned up."
- }, {
- "version": "3.5.4",
- "title": "tiktok support is back :D",
- "content": "you can download videos, sounds, and images from tiktok again!\nhuge thank you to @minzique for finding another api endpoint that works."
- }, {
- "version": "3.5.2",
- "title": "vk clips support, improved changelog system, and less bugs",
- "content": "new features: \n- added support for vk clips. cobalt now lets you download even more cringy videos!\n- added update history right to the changelog menu. it's not loaded by default to minimize page load time, but can be loaded upon pressing a button. probably someone will enjoy this.\n- as you've just read, cobalt now has on-demand blocks. they're rendered on server upon request and exist to prevent any unnecessary clutter by default. the first feature to use on-demand rendering is history of updates in changelog tab.\n\nchanges:\n- moved twitter entry to about tab and made it localized.\n- added clarity to what services exactly are supported in about tab.\n\nbug fixes:\n- cobalt should no longer crash to firefox users if they love to play around with user-agent switching.\n- vk videos of any resolution and aspect ratio should now be downloadable.\n- vk quality picking has been fixed after vk broke it for parsers on their side."
- }, {
- "version": "3.5",
- "title": "ui revamp and usability improvements",
- "content": "new features:\n- cobalt now lets you paste the link in your clipboard and download the file in a single press of a button.if your clipboard's latest content isn't a valid url, cobalt won't process or paste it. you can also hide the clipboard button in settings if you want to.\nunfortunately, the clipboard feature is not available to firefox users because mozilla didn't add proper support for clipboard api.\n- there's now a button to quickly clean the input area, right next to download button. it's really useful in case when you want to quickly save a bunch of videos and don't want to bother selecting text.\n- keyboard shortcuts! you love them, i love them, and now we can use them to perform quick actions in cobalt. use ctrl+v combo to paste the link without focusing the input area; press escape key to close the active popup or clean the input area; and if you didn't know, you can also press enter to download content from the link.\n\nnew looks:\n- main box has been revamped. it has lost its border, thick padding, and now feels light and fresh.\n- download button is now prettier, and has been tuned to make >> look just like the logo.\n- buttons on the bottom now actually look like buttons and are way more descriptive. no more #@+?$ bullshit. it's way easier to see and understand what each of them does.\n- bottom buttons are prettier and easier to use on a phone. they're bigger and stretch out to sides, making them easier to press.\n\nfixes:\n- it's now impossible to overlap multiple popups at once. no more mess if you decide to explore popups while waiting for request to process.\n- popup tabs have been slightly moved down to prevent popup content overlapping.\n- ui scalability has been improved."
- }]
-}
diff --git a/src/modules/changelog/changelogManager.js b/src/modules/changelog/changelogManager.js
deleted file mode 100644
index b8763fb5..00000000
--- a/src/modules/changelog/changelogManager.js
+++ /dev/null
@@ -1,46 +0,0 @@
-import { replaceBase } from "../../localization/manager.js";
-import { loadJSON } from "../sub/loadFromFs.js";
-
-let changelog = loadJSON('./src/modules/changelog/changelog.json')
-
-export default function(string) {
- try {
- const currentChangelog = changelog.current;
-
- switch (string) {
- case "version":
- return `v.${currentChangelog.version}${
- currentChangelog.date ? `· ${currentChangelog.date}` : ''
- }`
- case "title":
- return replaceBase(currentChangelog.title);
- case "banner":
- const currentBanner = changelog.current.banner;
- return currentBanner ? {
- ...currentBanner,
- url: `updateBanners/${currentBanner.file}`
- } : false;
- case "content":
- return replaceBase(currentChangelog.content);
- case "history":
- return changelog.history.map((log) => {
- const banner = log.banner;
- return {
- title: replaceBase(log.title),
- version: `v.${log.version}${
- log.date ? `· ${log.date}` : ''
- }`,
- content: replaceBase(log.content),
- banner: banner ? {
- ...banner,
- url: `updateBanners/${banner.file}`
- } : false,
- }
- });
- default:
- return replaceBase(changelog[string])
- }
- } catch (e) {
- return `!!CHANGELOG_${string}!!`
- }
-}
diff --git a/src/modules/config.js b/src/modules/config.js
deleted file mode 100644
index b774a8b6..00000000
--- a/src/modules/config.js
+++ /dev/null
@@ -1,57 +0,0 @@
-import UrlPattern from "url-pattern";
-import { loadJSON } from "./sub/loadFromFs.js";
-const config = loadJSON("./src/config.json");
-const packageJson = loadJSON("./package.json");
-const servicesConfigJson = loadJSON("./src/modules/processing/servicesConfig.json");
-
-Object.values(servicesConfigJson.config).forEach(service => {
- service.patterns = service.patterns.map(
- pattern => new UrlPattern(pattern, {
- segmentValueCharset: UrlPattern.defaultOptions.segmentValueCharset + '@\\.'
- })
- )
-})
-
-const
- apiURL = process.env.API_URL || '',
-
- // WEB mode related environment variables
- webEnvs = {
- webPort: process.env.WEB_PORT || 9001,
- webURL: process.env.WEB_URL || '',
- showSponsors: !!process.env.SHOW_SPONSORS,
- isBeta: !!process.env.IS_BETA,
- plausibleHostname: process.env.PLAUSIBLE_HOSTNAME,
- apiURL
- },
-
- // API mode related environment variables
- apiEnvs = {
- apiPort: process.env.API_PORT || 9000,
- apiName: process.env.API_NAME || 'unknown',
- corsWildcard: process.env.CORS_WILDCARD !== '0',
- corsURL: process.env.CORS_URL,
- cookiePath: process.env.COOKIE_PATH,
- processingPriority: process.env.PROCESSING_PRIORITY && parseInt(process.env.PROCESSING_PRIORITY),
- tiktokDeviceInfo: process.env.TIKTOK_DEVICE_INFO && JSON.parse(process.env.TIKTOK_DEVICE_INFO),
- apiURL
- }
-
-export const
- services = servicesConfigJson.config,
- audioIgnore = servicesConfigJson.audioIgnore,
- version = packageJson.version,
- streamLifespan = config.streamLifespan,
- maxVideoDuration = config.maxVideoDuration,
- genericUserAgent = config.genericUserAgent,
- repo = packageJson["bugs"]["url"].replace('/issues', ''),
- authorInfo = config.authorInfo,
- donations = config.donations,
- ffmpegArgs = config.ffmpegArgs,
- supportedAudio = config.supportedAudio,
- celebrations = config.celebrations,
- links = config.links,
- sponsors = config.sponsors,
- mode = (apiURL && !webEnvs.webURL) ? 'API' :
- (webEnvs.webURL && apiURL) ? 'WEB' : undefined,
- env = mode === 'API' ? apiEnvs : webEnvs
\ No newline at end of file
diff --git a/src/modules/emoji.js b/src/modules/emoji.js
deleted file mode 100644
index 82273ac4..00000000
--- a/src/modules/emoji.js
+++ /dev/null
@@ -1,66 +0,0 @@
-const names = {
- "🎶": "musical_notes",
- "🎬": "clapper_board",
- "🎉": "party_popper",
- "❓": "question_mark",
- "✨": "sparkles",
- "🪅": "pinata",
- "🪄": "magic_wand",
- "🐲": "dragon_face",
- "🀄": "dragon_face_wukko",
- "💸": "money_with_wings",
- "⚙️": "gear",
- "📋": "clipboard",
- "🎃": "pumpkin",
- "🎄": "christmas_tree",
- "🕯️": "candle",
- "😺": "cat",
- "🐶": "dog",
- "🎂": "cake",
- "🐘": "elephant",
- "🐦": "bird",
- "🐙": "octopus",
- "🔮": "crystal_ball",
- "💪": "biceps",
- "💖": "sparkling_heart",
- "👾": "alien_monster",
- "😿": "cat_crying",
- "🙀": "cat_flabbergasted",
- "🐱": "cat_smile",
- "❤️🩹": "mending_heart",
- "🔒": "locked",
- "🔍": "magnifying_glass",
- "🔗": "link",
- "⌨": "keyboard",
- "📑": "boring_document",
- "🧮": "abacus",
- "😸": "cat_grin",
- "📰": "newspaper",
- "🎞️": "film_frames",
- "🎧": "headphone",
- "📧": "email",
- "📬": "mailbox",
- "📢": "loudspeaker",
- "🔧": "wrench",
- "🫧": "bubbles"
-}
-let sizing = {
- 18: 0.8,
- 22: 0.4,
- 30: 0.7,
- 32: 0.8,
- 48: 0.9,
- 64: 0.9,
- 78: 0.9
-}
-export default function(emoji, size, disablePadding, fluent) {
- if (!size) size = 22;
- let padding = size !== 22 ? `margin-right:${sizing[size] ? sizing[size] : "0.4"}rem;` : false;
- if (disablePadding) padding = 'margin-right:0!important;';
-
- if (!names[emoji]) emoji = "❓";
-
- let filePath = `emoji/${names[emoji]}.svg`;
- if (fluent) filePath = `emoji/3d/${names[emoji]}.png`;
- return ``
-}
diff --git a/src/modules/pageRender/elements.js b/src/modules/pageRender/elements.js
deleted file mode 100644
index ae14cd88..00000000
--- a/src/modules/pageRender/elements.js
+++ /dev/null
@@ -1,270 +0,0 @@
-import { authorInfo, celebrations, sponsors, env } from "../config.js";
-import emoji from "../emoji.js";
-import { loadFile } from "../sub/loadFromFs.js";
-
-export const backButtonSVG = ``
-
-export const dropdownSVG = ``
-
-export const linkSVG = ''
-
-export function switcher(obj) {
- let items = ``;
- if (obj.name === "download") {
- items = obj.items;
- } else {
- for (let i = 0; i < obj.items.length; i++) {
- let classes = obj.items[i]["classes"] ? obj.items[i]["classes"] : [];
- items += ``
- }
- }
-
- if (obj.noParent) return `
${items}
`;
- return `
- ${obj.subtitle ? `
${obj.subtitle}
` : ``}
-
${items}
- ${obj.explanation ? `
${obj.explanation}
` : ``}
-
`
-}
-export function checkbox(obj) {
- let paddings = ["bottom-margin", "top-margin", "no-margin", "top-margin-only"];
- let checkboxes = ``;
- for (let i = 0; i < obj.length; i++) {
- let paddingClass = obj[i].padding && paddings.includes(obj[i].padding) ? ` ${obj[i].padding}` : '';
-
- checkboxes += ``
- }
- return checkboxes
-}
-export function sep(paddingType) {
- let paddingClass = ``
- switch(paddingType) {
- case 0:
- paddingClass += ` top-margin`;
- break;
- }
- return ``
-}
-export function popup(obj) {
- let classes = obj.classes ? obj.classes : [];
- let body = obj.body;
- if (Array.isArray(obj.body)) {
- body = ``
- for (let i = 0; i < obj.body.length; i++) {
- if (obj.body[i]["text"].length > 0) {
- classes = obj.body[i]["classes"] ?? []
- if (i !== obj.body.length - 1 && !obj.body[i]["nopadding"]) {
- classes.push("desc-padding")
- }
- body += obj.body[i]["raw"] ? obj.body[i]["text"] : `
`
-}
-export function socialLinks(lang) {
- let links = authorInfo.support[lang] ? authorInfo.support[lang] : authorInfo.support.default;
- let r = ``;
- for (let i in links) {
- r += socialLink(
- emoji(links[i].emoji), links[i].name, links[i].url
- )
- }
- return r
-}
-export function settingsCategory(obj) {
- return `