mirror of
https://github.com/faisalman/ua-parser-js.git
synced 2025-12-14 20:24:07 +03:00
Compare commits
10 Commits
2.0.7
...
2.0.5-pro-
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
5b5e33681f | ||
|
|
4e8c13cbb4 | ||
|
|
6ea2df63dc | ||
|
|
db06606acd | ||
|
|
138e6b7e55 | ||
|
|
99d59f7e4c | ||
|
|
768b622603 | ||
|
|
6f02da06e0 | ||
|
|
e6a085f710 | ||
|
|
37c61736c3 |
63
CHANGELOG.md
63
CHANGELOG.md
@@ -23,12 +23,8 @@
|
||||
- **Support for Custom/Predefined Extensions:**
|
||||
- Pass custom regexes or predefined extensions as a list to `UAParser()`
|
||||
|
||||
- **Support for CLI Processing:**
|
||||
- Directly parse user-agent strings from the command line:
|
||||
`npx ua-parser-js "<User-Agent>"`
|
||||
- Process batch data from files:
|
||||
`npx ua-parser-js --input-file=log.txt >> result.json` or
|
||||
`npx ua-parser-js --input-file=log.txt --output-file=result.json`
|
||||
- **Support for CLI Parsing:**
|
||||
- Parse a user-agent directly from the command line using `npx ua-parser-js "[User-Agent]"`
|
||||
|
||||
- **Enhanced Detection with Client Hints:**
|
||||
- `withClientHints()`: Improves detection accuracy by leveraging client hints
|
||||
@@ -54,66 +50,21 @@
|
||||
- `browser.name`, `browser.type`, `cpu.architecture`, `device.type`, `device.vendor`, `engine.name`, `os.name`
|
||||
|
||||
- **`'ua-parser-js/extensions'`**: Predefined extensions for various use cases:
|
||||
- `Bots`, `Crawlers`, `CLIs`, `Emails`, `ExtraDevices`, `Fetchers`, `InApps`, `Libraries`, `Mediaplayers`, `Vehicles`
|
||||
- `Bots`, `Crawlers`, `CLIs`, `Emails`, `ExtraDevices`, `Fetchers`, `InApps`, `Libraries`, `Mediaplayers`
|
||||
|
||||
- **`'ua-parser-js/helpers'`**: Provides utility methods to extend detection functionality:
|
||||
- `isFrozenUA()`: Checks if the user-agent matches a frozen/reduced user-agent pattern
|
||||
|
||||
- **`'ua-parser-js/bot-detection'`**:
|
||||
- `isAIAssistant()`: Checks if the user-agent is an AI assistant
|
||||
- `isAICrawler()`: Checks if the user-agent is an AI crawler
|
||||
- `getDeviceVendor()`: Guesses the device vendor based on its model name
|
||||
- `isAppleSilicon()`: Detects Apple Silicon device properties
|
||||
- `isAIBot()`: Checks if the user-agent is an AI bot
|
||||
- `isBot()`: Checks if the user-agent is a bot
|
||||
|
||||
- **`'ua-parser-js/browser-detection'`**:
|
||||
- `isChromeFamily()`: Checks if the browser is Chrome-based (uses Blink engine) — e.g., New Opera, New Edge, Vivaldi, Brave, Arc, etc.
|
||||
- `isElectron()`: Detects if current window is running within Electron
|
||||
- `isFromEU()`: Detects if current browser's timezone is from an EU country
|
||||
- `isFrozenUA()`: Checks if the user-agent matches a frozen/reduced user-agent pattern
|
||||
- `isStandalonePWA()`: Detects if current window is a standalone PWA
|
||||
|
||||
- **`'ua-parser-js/device-detection'`**:
|
||||
- `getDeviceVendor()`: Guesses the device vendor based on its model name
|
||||
- `isAppleSilicon()`: Detects Apple Silicon device properties
|
||||
|
||||
---
|
||||
|
||||
## Version 2.0.7
|
||||
|
||||
- Add support for chaining `withClientHints()` & `withFeatureCheck()`
|
||||
- Add new browser: Atlas, Steam
|
||||
- Add new device vendor: Anbernic, Logitech, Valve
|
||||
- Improve device detection: Xiaomi
|
||||
- Improve OS detection: iOS
|
||||
- Split `helpers` submodule into several new submodules:
|
||||
- `bot-detection`:
|
||||
- `isAIAssistant()`
|
||||
- `isAICrawler()`
|
||||
- `isBot()`
|
||||
- `browser-detection`
|
||||
- `isChromeFamily()`
|
||||
- `isElectron()`
|
||||
- `isFromEU()`
|
||||
- `isStandalonePWA()`
|
||||
- `device-detection`
|
||||
- `getDeviceVendor()`
|
||||
- `isAppleSilicon()`
|
||||
- Update `extensions` submodule:
|
||||
- Add new fetcher: Nova Act
|
||||
- Add new library: Bun, Dart, Deno, hackney, Node.js, rest-client, undici
|
||||
|
||||
## Version 2.0.6
|
||||
- Add new CLI feature: processing batch user-agent data from file and output as JSON
|
||||
- Fix `setUA()`: trim leading space from user-agent string input
|
||||
- Replace `undici` dependency with node's internal `Headers`
|
||||
- Add new browser: Bing, Qwant
|
||||
- Add new device vendor: Hisense, Wiko
|
||||
- Improve browser detection: Mozilla, Pale Moon
|
||||
- Improve CPU detection: 68k
|
||||
- Improve device detection: Apple, BlackBerry, Huawei, Nokia, Xiaomi
|
||||
- Improve OS detection: iOS 26
|
||||
- `extensions` submodule:
|
||||
- Add new fetcher: Discordbot, KeybaseBot, Slackbot, Slackbot-LinkExpanding, Slack-ImgProxy, Twitterbot
|
||||
- Add new crawler: Qwantbot-news, SurdotlyBot, SwiftBot
|
||||
|
||||
## Version 2.0.5
|
||||
|
||||
- Add new browser: Zalo
|
||||
|
||||
685
LICENSE.md
685
LICENSE.md
@@ -1,616 +1,73 @@
|
||||
# GNU AFFERO GENERAL PUBLIC LICENSE
|
||||
|
||||
Version 3, 19 November 2007
|
||||
|
||||
Copyright (C) 2007 Free Software Foundation, Inc.
|
||||
<https://fsf.org/>
|
||||
|
||||
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.
|
||||
# UAPARSER.JS PRO PERSONAL LICENSE
|
||||
|
||||
Version 2, July 2024
|
||||
|
||||
Copyright (C) 2023-2024 Faisal Salman <f+ua-parser-js@faisalman.com>
|
||||
|
||||
---
|
||||
|
||||
## Definitions
|
||||
|
||||
"We" are the team behind UAParser.js.
|
||||
|
||||
"You" are the individual who is responsible for purchasing this license.
|
||||
|
||||
"The Code" is UAParser.js.
|
||||
|
||||
"Project" is what you built with The Code.
|
||||
|
||||
---
|
||||
|
||||
## License
|
||||
|
||||
We retain all title, intellectual property, and ownership rights to The Code.
|
||||
|
||||
The Code is licensed, not sold, to You for use solely subject to the terms and conditions detailed here.
|
||||
|
||||
We grant You (and only You) a personal, limited, non-exclusive, non-transferable, non-sublicensable, royalty-free right to use, copy, and modify The Code.
|
||||
|
||||
This license is only valid for You as one (1) individual and cannot be transferred to another individual or organization.
|
||||
|
||||
---
|
||||
|
||||
## Rights
|
||||
|
||||
You may use and modify The Code to create as many personal, hobby, educational, and other non-profit projects as you want for yourself.
|
||||
|
||||
You may create any number of copies of The Code for yourself.
|
||||
|
||||
You have the right to get lifetime updates and one (1) year of support, starting from the time you make the purchase.
|
||||
|
||||
---
|
||||
|
||||
## Restrictions
|
||||
|
||||
You may not use or modify The Code in such a way that it may be used directly for commercial purposes.
|
||||
|
||||
You may not redistribute The Code, as-is or modified, except as a part of a Project that you made for yourself.
|
||||
|
||||
You may not deliver a Project that contains The Code as an open-source Project that might be used for commercial purposes by the general public, except with our written consent.
|
||||
|
||||
You may not use The Code for unlawful, inappropriate, illegal, or offensive purposes.
|
||||
|
||||
---
|
||||
|
||||
## Limitations
|
||||
|
||||
The Code is provided 'as is' without warranty of any kind, expressed or implied.
|
||||
|
||||
We shall not be liable for any damages, including but not limited to, direct, indirect, special, incidental, or consequential damages or losses that occur by the use of The Code.
|
||||
|
||||
We reserve the right to discontinue the lifetime updates for The Code at any time, with or without notice.
|
||||
|
||||
We offer support only for questions within the scope of The Code's functionality or related issues at our sole discretion.
|
||||
|
||||
---
|
||||
|
||||
## Termination
|
||||
|
||||
This license is effective indefinitely but can be revoked at any time if there is a violation of any of the terms.
|
||||
|
||||
---
|
||||
|
||||
END OF TERMS AND CONDITIONS
|
||||
283
README.md
283
README.md
@@ -1,280 +1,29 @@
|
||||
#### Featured Sponsors
|
||||
# UAParser.js PRO Personal License
|
||||
|
||||
[](https://ref.wisprflow.ai/Rxj3n8H)
|
||||
Thank you for choosing the UAParser.js PRO Personal License.
|
||||
|
||||
---
|
||||
Please be aware that using this package without a valid license purchase is strictly prohibited and constitutes a violation of applicable copyright laws.
|
||||
|
||||
[](https://uaparser.dev)
|
||||
[](https://uaparser.dev)
|
||||
[](https://uaparser.dev)
|
||||
[](https://uaparser.dev)
|
||||
An exception applies if the package is used solely as a part of a product developed by a valid license holder, in accordance with their license terms.
|
||||
|
||||
<p align="center">
|
||||
<a href="https://www.npmjs.com/package/ua-parser-js"><img src="https://img.shields.io/npm/dw/ua-parser-js?color=red&logo=npm&label=NPM%20DOWNLOADS&style=for-the-badge"></a>
|
||||
<a href="https://www.jsdelivr.com/package/npm/ua-parser-js"><img src="https://img.shields.io/jsdelivr/gh/hw/faisalman/ua-parser-js?logo=jsdelivr&style=for-the-badge"></a>
|
||||
<a href="https://github.com/faisalman/ua-parser-js"><img src="https://img.shields.io/github/stars/faisalman/ua-parser-js?color=yellow&logo=github&style=for-the-badge"></a>
|
||||
<a href="https://bundlephobia.com/package/ua-parser-js@1.0.35"><img src="https://img.shields.io/bundlephobia/minzip/ua-parser-js?logo=hackthebox&logoColor=white&style=for-the-badge"/></a>
|
||||
<a href="https://github.com/faisalman/ua-parser-js/graphs/contributors"><img src="https://img.shields.io/github/contributors/faisalman/ua-parser-js?color=purple&logo=githubsponsors&style=for-the-badge"></a>
|
||||
<a href="https://www.npmjs.com/package/ua-parser-js"><img src="https://img.shields.io/npm/v/ua-parser-js.svg?logo=npm&color=red&style=for-the-badge"></a>
|
||||
<a href="https://cdnjs.com/libraries/UAParser.js"><img src="https://img.shields.io/cdnjs/v/UAParser.js.svg?color=orange&style=for-the-badge"></a>
|
||||
<img src="https://img.shields.io/ossf-scorecard/github.com/faisalman/ua-parser-js?label=openssf%20scorecard&style=for-the-badge">
|
||||
<a target="_blank" href="https://discord.com/channels/1406959509087453236/1406959509930381375"><img alt="Discord invite" src="https://dcbadge.limes.pink/api/server/https://discord.com/channels/1406959509087453236/1406959509930381375"></a>
|
||||
</p>
|
||||
If you have not yet purchased a license, you may do so at https://store.faisalman.com.
|
||||
|
||||
# UAParser.js
|
||||
|
||||
The most comprehensive, compact, and up-to-date JavaScript library to detect user's browser, OS, CPU, and device type/model. Also detect bots, apps, and more. Runs seamlessly in the browser (client-side) or Node.js (server-side).
|
||||
|
||||
# Demo
|
||||
|
||||
* Live demo: https://uaparser.dev
|
||||
# Download
|
||||
|
||||
```sh
|
||||
npm install @ua-parser-js/pro-personal
|
||||
```
|
||||
|
||||
# Documentation
|
||||
|
||||
* `version 1.x` : https://github.com/faisalman/ua-parser-js/tree/1.0.x#documentation
|
||||
* `version 2.x` : https://docs.uaparser.dev
|
||||
https://docs.uaparser.dev
|
||||
|
||||
Before upgrading from `v0.7` / `v1.0`, please read [CHANGELOG](CHANGELOG.md) to
|
||||
see what's new & breaking.
|
||||
```js
|
||||
import { UAParser } from '@ua-parser-js/pro-personal';
|
||||
```
|
||||
|
||||
# Package & Pricing
|
||||
# License
|
||||
|
||||
<table>
|
||||
<thead>
|
||||
<tr>
|
||||
<th></th>
|
||||
<th colspan="2">Open-Source Editions</th>
|
||||
<th colspan="3">PRO / Commercial Editions</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<tr>
|
||||
<td>License options</td>
|
||||
<td>MIT (v1.x)</td>
|
||||
<td>AGPL (v2.x)</td>
|
||||
<td>PRO Personal</td>
|
||||
<td>PRO Business</td>
|
||||
<td>PRO Enterprise</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>Browser Detection</td>
|
||||
<td><a href="#demo" title="Basic detection">⚠️</a></td>
|
||||
<td>✅</td>
|
||||
<td>✅</td>
|
||||
<td>✅</td>
|
||||
<td>✅</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>CPU Detection</td>
|
||||
<td><a href="#demo" title="Basic detection">⚠️</a></td>
|
||||
<td>✅</td>
|
||||
<td>✅</td>
|
||||
<td>✅</td>
|
||||
<td>✅</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>Device Detection</td>
|
||||
<td><a href="#demo" title="Basic detection">⚠️</a></td>
|
||||
<td>✅</td>
|
||||
<td>✅</td>
|
||||
<td>✅</td>
|
||||
<td>✅</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>Rendering Engine Detection</td>
|
||||
<td><a href="#demo" title="Basic detection">⚠️</a></td>
|
||||
<td>✅</td>
|
||||
<td>✅</td>
|
||||
<td>✅</td>
|
||||
<td>✅</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>OS detection</td>
|
||||
<td><a href="#demo" title="Basic detection">⚠️</a></td>
|
||||
<td>✅</td>
|
||||
<td>✅</td>
|
||||
<td>✅</td>
|
||||
<td>✅</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>Enhanced+ Accuracy</td>
|
||||
<td>❌</td>
|
||||
<td>✅</td>
|
||||
<td>✅</td>
|
||||
<td>✅</td>
|
||||
<td>✅</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>Bot Detection</td>
|
||||
<td>❌</td>
|
||||
<td>✅</td>
|
||||
<td>✅</td>
|
||||
<td>✅</td>
|
||||
<td>✅</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>AI Detection</td>
|
||||
<td>❌</td>
|
||||
<td>✅</td>
|
||||
<td>✅</td>
|
||||
<td>✅</td>
|
||||
<td>✅</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>Extra Detections (Apps, Libs, Emails, Media Players, Crawlers, and more)</td>
|
||||
<td>❌</td>
|
||||
<td>✅</td>
|
||||
<td>✅</td>
|
||||
<td>✅</td>
|
||||
<td>✅</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>Client Hints Support</td>
|
||||
<td>❌</td>
|
||||
<td>✅</td>
|
||||
<td>✅</td>
|
||||
<td>✅</td>
|
||||
<td>✅</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>CommonJS Support</td>
|
||||
<td>✅</td>
|
||||
<td>✅</td>
|
||||
<td>✅</td>
|
||||
<td>✅</td>
|
||||
<td>✅</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>ESM Support</td>
|
||||
<td>❌</td>
|
||||
<td>✅</td>
|
||||
<td>✅</td>
|
||||
<td>✅</td>
|
||||
<td>✅</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>TypeScript Definitions</td>
|
||||
<td><a href="#demo" title="Community version">✅</a></td>
|
||||
<td>✅</td>
|
||||
<td>✅</td>
|
||||
<td>✅</td>
|
||||
<td>✅</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>npm Module Available</td>
|
||||
<td>✅</td>
|
||||
<td>✅</td>
|
||||
<td>✅</td>
|
||||
<td>✅</td>
|
||||
<td>✅</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>Direct Downloads Available</td>
|
||||
<td>✅</td>
|
||||
<td>✅</td>
|
||||
<td>✅</td>
|
||||
<td>✅</td>
|
||||
<td>✅</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>Commercial Use Allowed</td>
|
||||
<td>✅</td>
|
||||
<td>✅</td>
|
||||
<td>❌</td>
|
||||
<td>✅</td>
|
||||
<td>✅</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>Permissive (non-Copyleft) License</td>
|
||||
<td>✅</td>
|
||||
<td><strong title="Copyleft license">❌</strong></td>
|
||||
<td>✅</td>
|
||||
<td>✅</td>
|
||||
<td>✅</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>No Open-Source Obligations</td>
|
||||
<td>✅</td>
|
||||
<td><strong title="Copyleft license">❌</strong></td>
|
||||
<td>✅</td>
|
||||
<td>✅</td>
|
||||
<td>✅</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>Unlimited End-Products</td>
|
||||
<td>✅</td>
|
||||
<td>✅</td>
|
||||
<td>✅</td>
|
||||
<td><strong title="1 end-product per license">❌</strong></td>
|
||||
<td>✅</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>Unlimited Deployments</td>
|
||||
<td>✅</td>
|
||||
<td>✅</td>
|
||||
<td>✅</td>
|
||||
<td><strong title="1 TLD or deliverable per license">❌</strong></td>
|
||||
<td>✅</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>1-year Product Support</td>
|
||||
<td>❌</td>
|
||||
<td>❌</td>
|
||||
<td>✅</td>
|
||||
<td>✅</td>
|
||||
<td>✅</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>Lifetime Updates</td>
|
||||
<td>✅</td>
|
||||
<td>✅</td>
|
||||
<td>✅</td>
|
||||
<td>✅</td>
|
||||
<td>✅</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>Price</td>
|
||||
<td><strong title="Pay as you want">FREE<sup>*</sup> (<a target="_blank" href="https://raw.githubusercontent.com/faisalman/ua-parser-js/1.0.x/license.md">License</a>)</strong></td>
|
||||
<td><strong title="Pay as you want">FREE<sup>*</sup> (<a target="_blank" href="https://raw.githubusercontent.com/faisalman/ua-parser-js/master/LICENSE.md">License</a>)</strong></td>
|
||||
<td><strong title="$14 (one-time fee)">$14 (<a target="_blank" href="https://raw.githubusercontent.com/faisalman/ua-parser-js/pro-personal/LICENSE.md">License</a>)</strong></td>
|
||||
<td><strong title="$29 (one-time fee)">$29 (<a target="_blank" href="https://raw.githubusercontent.com/faisalman/ua-parser-js/pro-business/LICENSE.md">License</a>)</strong></td>
|
||||
<td><strong title="$599 (one-time fee)">$599 (<a target="_blank" href="https://raw.githubusercontent.com/faisalman/ua-parser-js/pro-enterprise/LICENSE.md">License</a>)</strong></td>
|
||||
</tr>
|
||||
</tbody>
|
||||
<tfoot>
|
||||
<tr>
|
||||
<th align="right" colspan="6">
|
||||
<h3><a target="_blank" href="https://store.faisalman.com/checkout/buy/e236ea87-9b2b-400e-9683-24367f731b35"> GET THE PRO PACKAGES 📥</a></h3>
|
||||
</th>
|
||||
</tr>
|
||||
</tfoot>
|
||||
</table>
|
||||
UAParser.js PRO Personal
|
||||
|
||||
# Development
|
||||
|
||||
## Contributors
|
||||
|
||||
Please read [CONTRIBUTING](CONTRIBUTING.md) guide first for the instruction details.
|
||||
|
||||
<a href="https://github.com/faisalman/ua-parser-js/graphs/contributors">
|
||||
<img src="https://contrib.rocks/image?repo=faisalman/ua-parser-js" />
|
||||
</a>
|
||||
|
||||
Made with [contributors-img](https://contrib.rocks).
|
||||
|
||||
## Backers & Sponsors
|
||||
|
||||
Support the **open-source editions** of UAParser.js through one of the following options:
|
||||
|
||||
[](https://opencollective.com/ua-parser-js)
|
||||
[](https://github.com/sponsors/faisalman)
|
||||
[](https://paypal.me/faisalman)
|
||||
[](https://store.faisalman.com/buy/3d71f2f3-cf4d-473c-892a-9d4497c890be)
|
||||
|
||||
<a href="https://opencollective.com/ua-parser-js"><img src="https://opencollective.com/ua-parser-js/organizations.svg?avatarHeight=64"></a>
|
||||
<a href="https://opencollective.com/ua-parser-js"><img src="https://opencollective.com/ua-parser-js/individuals.svg?avatarHeight=64"></a>
|
||||
Copyright (c) 2023-2024 Faisal Salman <<f@faisalman.com>>
|
||||
|
||||
6
dist/ua-parser.min.js
vendored
6
dist/ua-parser.min.js
vendored
File diff suppressed because one or more lines are too long
6
dist/ua-parser.min.mjs
vendored
6
dist/ua-parser.min.mjs
vendored
File diff suppressed because one or more lines are too long
6
dist/ua-parser.pack.js
vendored
6
dist/ua-parser.pack.js
vendored
File diff suppressed because one or more lines are too long
6
dist/ua-parser.pack.mjs
vendored
6
dist/ua-parser.pack.mjs
vendored
File diff suppressed because one or more lines are too long
52
package-lock.json
generated
52
package-lock.json
generated
@@ -1,12 +1,12 @@
|
||||
{
|
||||
"name": "ua-parser-js",
|
||||
"version": "2.0.7",
|
||||
"name": "@ua-parser-js/pro-personal",
|
||||
"version": "2.0.5",
|
||||
"lockfileVersion": 3,
|
||||
"requires": true,
|
||||
"packages": {
|
||||
"": {
|
||||
"name": "ua-parser-js",
|
||||
"version": "2.0.7",
|
||||
"name": "@ua-parser-js/pro-personal",
|
||||
"version": "2.0.5",
|
||||
"funding": [
|
||||
{
|
||||
"type": "opencollective",
|
||||
@@ -21,19 +21,20 @@
|
||||
"url": "https://github.com/sponsors/faisalman"
|
||||
}
|
||||
],
|
||||
"license": "AGPL-3.0-or-later",
|
||||
"license": "SEE LICENSE IN LICENSE.md",
|
||||
"dependencies": {
|
||||
"detect-europe-js": "^0.1.2",
|
||||
"is-standalone-pwa": "^0.1.1",
|
||||
"ua-is-frozen": "^0.1.2"
|
||||
"ua-is-frozen": "^0.1.2",
|
||||
"undici": "^7.12.0"
|
||||
},
|
||||
"bin": {
|
||||
"ua-parser-js": "script/cli.js"
|
||||
"pro-personal": "script/cli.js"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@babel/parser": "7.15.8",
|
||||
"@babel/traverse": "7.23.2",
|
||||
"@playwright/test": "^1.57.0",
|
||||
"@playwright/test": "^1.49.0",
|
||||
"jshint": "~2.13.6",
|
||||
"mocha": "~8.2.0",
|
||||
"requirejs": "2.3.2",
|
||||
@@ -343,13 +344,12 @@
|
||||
}
|
||||
},
|
||||
"node_modules/@playwright/test": {
|
||||
"version": "1.57.0",
|
||||
"resolved": "https://registry.npmjs.org/@playwright/test/-/test-1.57.0.tgz",
|
||||
"integrity": "sha512-6TyEnHgd6SArQO8UO2OMTxshln3QMWBtPGrOCgs3wVEmQmwyuNtB10IZMfmYDE0riwNR1cu4q+pPcxMVtaG3TA==",
|
||||
"version": "1.49.0",
|
||||
"resolved": "https://registry.npmjs.org/@playwright/test/-/test-1.49.0.tgz",
|
||||
"integrity": "sha512-DMulbwQURa8rNIQrf94+jPJQ4FmOVdpE5ZppRNvWVjvhC+6sOeo28r8MgIpQRYouXRtt/FCCXU7zn20jnHR4Qw==",
|
||||
"dev": true,
|
||||
"license": "Apache-2.0",
|
||||
"dependencies": {
|
||||
"playwright": "1.57.0"
|
||||
"playwright": "1.49.0"
|
||||
},
|
||||
"bin": {
|
||||
"playwright": "cli.js"
|
||||
@@ -2043,13 +2043,12 @@
|
||||
}
|
||||
},
|
||||
"node_modules/playwright": {
|
||||
"version": "1.57.0",
|
||||
"resolved": "https://registry.npmjs.org/playwright/-/playwright-1.57.0.tgz",
|
||||
"integrity": "sha512-ilYQj1s8sr2ppEJ2YVadYBN0Mb3mdo9J0wQ+UuDhzYqURwSoW4n1Xs5vs7ORwgDGmyEh33tRMeS8KhdkMoLXQw==",
|
||||
"version": "1.49.0",
|
||||
"resolved": "https://registry.npmjs.org/playwright/-/playwright-1.49.0.tgz",
|
||||
"integrity": "sha512-eKpmys0UFDnfNb3vfsf8Vx2LEOtflgRebl0Im2eQQnYMA4Aqd+Zw8bEOB+7ZKvN76901mRnqdsiOGKxzVTbi7A==",
|
||||
"dev": true,
|
||||
"license": "Apache-2.0",
|
||||
"dependencies": {
|
||||
"playwright-core": "1.57.0"
|
||||
"playwright-core": "1.49.0"
|
||||
},
|
||||
"bin": {
|
||||
"playwright": "cli.js"
|
||||
@@ -2062,11 +2061,10 @@
|
||||
}
|
||||
},
|
||||
"node_modules/playwright-core": {
|
||||
"version": "1.57.0",
|
||||
"resolved": "https://registry.npmjs.org/playwright-core/-/playwright-core-1.57.0.tgz",
|
||||
"integrity": "sha512-agTcKlMw/mjBWOnD6kFZttAAGHgi/Nw0CZ2o6JqWSbMlI219lAFLZZCyqByTsvVAJq5XA5H8cA6PrvBRpBWEuQ==",
|
||||
"version": "1.49.0",
|
||||
"resolved": "https://registry.npmjs.org/playwright-core/-/playwright-core-1.49.0.tgz",
|
||||
"integrity": "sha512-R+3KKTQF3npy5GTiKH/T+kdhoJfJojjHESR1YEWhYuEKRVfVaxH3+4+GvXE5xyCngCxhxnykk0Vlah9v8fs3jA==",
|
||||
"dev": true,
|
||||
"license": "Apache-2.0",
|
||||
"bin": {
|
||||
"playwright-core": "cli.js"
|
||||
},
|
||||
@@ -2080,7 +2078,6 @@
|
||||
"integrity": "sha512-xiqMQR4xAeHTuB9uWm+fFRcIOgKBMiOBP+eXiyT7jsgVCq1bkVygt00oASowB7EdtpOHaaPgKt812P9ab+DDKA==",
|
||||
"dev": true,
|
||||
"hasInstallScript": true,
|
||||
"license": "MIT",
|
||||
"optional": true,
|
||||
"os": [
|
||||
"darwin"
|
||||
@@ -2696,6 +2693,15 @@
|
||||
"node": ">=0.8.0"
|
||||
}
|
||||
},
|
||||
"node_modules/undici": {
|
||||
"version": "7.12.0",
|
||||
"resolved": "https://registry.npmjs.org/undici/-/undici-7.12.0.tgz",
|
||||
"integrity": "sha512-GrKEsc3ughskmGA9jevVlIOPMiiAHJ4OFUtaAH+NhfTUSiZ1wMPIQqQvAJUrJspFXJt3EBWgpAeoHEDVT1IBug==",
|
||||
"license": "MIT",
|
||||
"engines": {
|
||||
"node": ">=20.18.1"
|
||||
}
|
||||
},
|
||||
"node_modules/validate-npm-package-license": {
|
||||
"version": "3.0.4",
|
||||
"resolved": "https://registry.npmjs.org/validate-npm-package-license/-/validate-npm-package-license-3.0.4.tgz",
|
||||
|
||||
38
package.json
38
package.json
@@ -1,25 +1,25 @@
|
||||
{
|
||||
"title": "UAParser.js",
|
||||
"name": "ua-parser-js",
|
||||
"version": "2.0.7",
|
||||
"title": "UAParser.js PRO Personal",
|
||||
"name": "@ua-parser-js/pro-personal",
|
||||
"version": "2.0.5",
|
||||
"author": "Faisal Salman <f@faisalman.com> (http://faisalman.com)",
|
||||
"description": "Detect Browser, Engine, OS, CPU, and Device type/model from User-Agent & Client Hints data. Supports browser & node.js environment",
|
||||
"keywords": [
|
||||
"user-agent",
|
||||
"client-hints",
|
||||
"parser",
|
||||
"browser",
|
||||
"engine",
|
||||
"os",
|
||||
"device",
|
||||
"cpu",
|
||||
"jquery-plugin",
|
||||
"ecosystem:jquery",
|
||||
"ua-parser-js",
|
||||
"browser-detection",
|
||||
"device-detection",
|
||||
"os-detection",
|
||||
"bot-detection",
|
||||
"ai-detection",
|
||||
"app-detection",
|
||||
"crawler-detection"
|
||||
"bot-detection"
|
||||
],
|
||||
"homepage": "https://uaparser.dev",
|
||||
"contributors": [
|
||||
@@ -190,21 +190,6 @@
|
||||
"import": "./src/main/ua-parser.mjs",
|
||||
"types": "./src/main/ua-parser.d.ts"
|
||||
},
|
||||
"./bot-detection": {
|
||||
"require": "./src/bot-detection/bot-detection.js",
|
||||
"import": "./src/bot-detection/bot-detection.mjs",
|
||||
"types": "./src/bot-detection/bot-detection.d.ts"
|
||||
},
|
||||
"./browser-detection": {
|
||||
"require": "./src/browser-detection/browser-detection.js",
|
||||
"import": "./src/browser-detection/browser-detection.mjs",
|
||||
"types": "./src/browser-detection/browser-detection.d.ts"
|
||||
},
|
||||
"./device-detection": {
|
||||
"require": "./src/device-detection/device-detection.js",
|
||||
"import": "./src/device-detection/device-detection.mjs",
|
||||
"types": "./src/device-detection/device-detection.d.ts"
|
||||
},
|
||||
"./enums": {
|
||||
"require": "./src/enums/ua-parser-enums.js",
|
||||
"import": "./src/enums/ua-parser-enums.mjs",
|
||||
@@ -235,18 +220,19 @@
|
||||
"test:eslint": "eslint src && eslint script",
|
||||
"test:jshint": "jshint src/main",
|
||||
"test:lockfile-lint": "npx lockfile-lint -p package-lock.json",
|
||||
"test:mocha": "mocha --recursive test/unit",
|
||||
"test:mocha": "mocha test/unit",
|
||||
"test:playwright": "npx playwright install && playwright test test/e2e --browser all"
|
||||
},
|
||||
"dependencies": {
|
||||
"detect-europe-js": "^0.1.2",
|
||||
"is-standalone-pwa": "^0.1.1",
|
||||
"ua-is-frozen": "^0.1.2"
|
||||
"ua-is-frozen": "^0.1.2",
|
||||
"undici": "^7.12.0"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@babel/parser": "7.15.8",
|
||||
"@babel/traverse": "7.23.2",
|
||||
"@playwright/test": "^1.57.0",
|
||||
"@playwright/test": "^1.49.0",
|
||||
"jshint": "~2.13.6",
|
||||
"mocha": "~8.2.0",
|
||||
"requirejs": "2.3.2",
|
||||
@@ -258,7 +244,7 @@
|
||||
"type": "git",
|
||||
"url": "https://github.com/faisalman/ua-parser-js.git"
|
||||
},
|
||||
"license": "AGPL-3.0-or-later",
|
||||
"license": "SEE LICENSE IN LICENSE.md",
|
||||
"engines": {
|
||||
"node": "*"
|
||||
},
|
||||
|
||||
@@ -40,24 +40,6 @@ const files = [
|
||||
...defaultReplacements.mjs
|
||||
]
|
||||
},
|
||||
{
|
||||
src : 'src/bot-detection/bot-detection.js',
|
||||
dest :'src/bot-detection/bot-detection.mjs',
|
||||
title : 'Generated ESM version of ua-parser-js/bot-detection',
|
||||
replacements : [...defaultReplacements.mjs]
|
||||
},
|
||||
{
|
||||
src : 'src/browser-detection/browser-detection.js',
|
||||
dest :'src/browser-detection/browser-detection.mjs',
|
||||
title : 'Generated ESM version of ua-parser-js/browser-detection',
|
||||
replacements : [...defaultReplacements.mjs]
|
||||
},
|
||||
{
|
||||
src : 'src/device-detection/device-detection.js',
|
||||
dest :'src/device-detection/device-detection.mjs',
|
||||
title : 'Generated ESM version of ua-parser-js/device-detection',
|
||||
replacements : [...defaultReplacements.mjs]
|
||||
},
|
||||
{
|
||||
src : 'src/enums/ua-parser-enums.js',
|
||||
dest :'src/enums/ua-parser-enums.mjs',
|
||||
|
||||
@@ -1,94 +1,4 @@
|
||||
#!/usr/bin/env node
|
||||
|
||||
try {
|
||||
const fs = require('node:fs');
|
||||
const path = require('node:path');
|
||||
const { performance } = require('node:perf_hooks');
|
||||
const readline = require('node:readline');
|
||||
const { parseArgs } = require('node:util');
|
||||
const UAParser = require('../src/main/ua-parser');
|
||||
const { Bots, Emails, ExtraDevices, InApps, Vehicles } = require('../src/extensions/ua-parser-extensions');
|
||||
|
||||
if (!process.argv[2].startsWith('-')) {
|
||||
|
||||
const results = process.argv.slice(2).map(ua => UAParser(ua, [Bots, Emails, ExtraDevices, InApps, Vehicles]));
|
||||
console.log(JSON.stringify(results, null, 4));
|
||||
process.exit(0);
|
||||
|
||||
} else if (['-h', '--help'].includes(process.argv[2])) {
|
||||
|
||||
console.log('Usage: npx ua-parser-js <string>');
|
||||
console.log(' or npx ua-parser-js --input-file <filepath> [--output-file <filepath>]');
|
||||
console.log('-i, --input-file');
|
||||
console.log('-o, --output-file');
|
||||
process.exit(0);
|
||||
|
||||
} else {
|
||||
|
||||
const startPerf = performance.now();
|
||||
const {
|
||||
values: {
|
||||
'input-file': inputFile,
|
||||
'output-file': outputFile
|
||||
},
|
||||
} = parseArgs({
|
||||
options: {
|
||||
'input-file': { type: 'string', short: 'i' },
|
||||
'output-file': { type: 'string', short: 'o' }
|
||||
}
|
||||
});
|
||||
|
||||
if (!inputFile) {
|
||||
console.error('Input file must be present');
|
||||
process.exit(1);
|
||||
}
|
||||
|
||||
const inputPath = path.resolve(__dirname, inputFile);
|
||||
const outputPath = outputFile ? path.resolve(__dirname, outputFile) : null;
|
||||
|
||||
if (!fs.existsSync(inputPath)) {
|
||||
console.error(`Input file not found: ${inputPath}`);
|
||||
process.exit(1);
|
||||
}
|
||||
|
||||
const inputStream = fs.createReadStream(inputPath, 'utf8');
|
||||
const rl = readline.createInterface({
|
||||
input: inputStream,
|
||||
crlfDelay: Infinity
|
||||
});
|
||||
|
||||
const outputStream = outputPath ? fs.createWriteStream(outputPath, { encoding : 'utf8' }) : process.stdout;
|
||||
|
||||
const uap = new UAParser([Bots, Emails, ExtraDevices, InApps, Vehicles]);
|
||||
let lineNumber = 0;
|
||||
|
||||
outputStream.write('[\n');
|
||||
|
||||
rl.on('line', line => {
|
||||
const result = uap.setUA(line).getResult();
|
||||
const json = JSON.stringify(result, null, 4);
|
||||
if (lineNumber > 0) outputStream.write(',\n');
|
||||
outputStream.write(json);
|
||||
lineNumber++;
|
||||
});
|
||||
|
||||
rl.on('close', () => {
|
||||
outputStream.write('\n]');
|
||||
if (outputPath) {
|
||||
outputStream.end(() => {
|
||||
const finishPerf = performance.now();
|
||||
console.log(`Done!`);
|
||||
console.log(`Number of lines found: ${lineNumber}`);
|
||||
console.log(`Task finished in: ${(finishPerf - startPerf).toFixed(3)}ms`);
|
||||
console.log(`Output written to: ${outputPath}`);
|
||||
process.exit(0);
|
||||
});
|
||||
} else {
|
||||
process.exit(0);
|
||||
}
|
||||
});
|
||||
}
|
||||
} catch (err) {
|
||||
console.error(err);
|
||||
process.exit(1);
|
||||
}
|
||||
const UAParser = require('ua-parser-js');
|
||||
console.log(JSON.stringify(process.argv.slice(2).map(ua => UAParser(ua)), null, 4));
|
||||
7
src/bot-detection/bot-detection.d.ts
vendored
7
src/bot-detection/bot-detection.d.ts
vendored
@@ -1,7 +0,0 @@
|
||||
// Type definitions for bot-detection submodule of UAParser.js v2.0.7
|
||||
// Project: https://github.com/faisalman/ua-parser-js
|
||||
// Definitions by: Faisal Salman <https://github.com/faisalman>
|
||||
|
||||
export function isAIAssistant(ua: string): boolean;
|
||||
export function isAICrawler(ua: string): boolean;
|
||||
export function isBot(ua: string): boolean;
|
||||
@@ -1,188 +0,0 @@
|
||||
//////////////////////////////////////////////////
|
||||
/* bot-detection submodule of UAParser.js v2.0.7
|
||||
https://github.com/faisalman/ua-parser-js
|
||||
Author: Faisal Salman <f@faisalman.com>
|
||||
AGPLv3 License */
|
||||
/////////////////////////////////////////////////
|
||||
|
||||
/*jshint esversion: 6 */
|
||||
|
||||
const { UAParser } = require('../main/ua-parser');
|
||||
const { Bots, Crawlers, Fetchers } = require('../extensions/ua-parser-extensions');
|
||||
const { BrowserType, Extension } = require('../enums/ua-parser-enums');
|
||||
const { Crawler, Fetcher } = Extension.BrowserName;
|
||||
|
||||
class BotList {
|
||||
constructor(ext, prop, list) {
|
||||
this.ext = ext;
|
||||
this.prop = prop;
|
||||
this.list = list.map(x => x.toLowerCase());
|
||||
}
|
||||
includes(ua) {
|
||||
return this.list.includes(
|
||||
(typeof ua === 'string' ?
|
||||
new UAParser(ua, this.ext).getBrowser() :
|
||||
ua.browser
|
||||
)[this.prop]?.toLowerCase());
|
||||
}
|
||||
}
|
||||
|
||||
const BotTypes = new BotList(Bots, 'type', [
|
||||
BrowserType.CLI,
|
||||
BrowserType.CRAWLER,
|
||||
BrowserType.FETCHER,
|
||||
BrowserType.LIBRARY
|
||||
]);
|
||||
|
||||
const AIAssistants = new BotList(Fetchers, 'name', [
|
||||
|
||||
// Amazon
|
||||
Fetcher.AMAZON_NOVA_ACT,
|
||||
|
||||
// Anthropic
|
||||
Fetcher.ANTHROPIC_CLAUDE_USER,
|
||||
|
||||
// Cohere
|
||||
Fetcher.COHERE_AI,
|
||||
|
||||
// DuckDuckGo
|
||||
Fetcher.DUCKDUCKGO_ASSISTBOT,
|
||||
|
||||
// Google
|
||||
Fetcher.GOOGLE_GEMINI_DEEP_RESEARCH,
|
||||
|
||||
// Mistral AI
|
||||
Fetcher.MISTRALAI_USER,
|
||||
|
||||
// OpenAI
|
||||
Fetcher.OPENAI_CHATGPT_USER,
|
||||
|
||||
// Perplexity
|
||||
Fetcher.PERPLEXITY_USER
|
||||
]);
|
||||
|
||||
const AICrawlers = new BotList(Crawlers, 'name', [
|
||||
|
||||
// AI2
|
||||
Crawler.AI2_BOT,
|
||||
|
||||
// Amazon
|
||||
Crawler.AMAZON_BOT,
|
||||
|
||||
// Anthropic
|
||||
Crawler.ANTHROPIC_AI,
|
||||
Crawler.ANTHROPIC_CLAUDE_BOT,
|
||||
Crawler.ANTHROPIC_CLAUDE_SEARCHBOT,
|
||||
Crawler.ANTHROPIC_CLAUDE_WEB,
|
||||
|
||||
// Apple
|
||||
Crawler.APPLE_BOT,
|
||||
Crawler.APPLE_BOT_EXTENDED,
|
||||
|
||||
// Brave
|
||||
Crawler.BRAVE_BOT,
|
||||
|
||||
// ByteDance
|
||||
Crawler.BYTEDANCE_BYTESPIDER,
|
||||
Crawler.BYTEDANCE_TIKTOKSPIDER,
|
||||
|
||||
// Cohere
|
||||
Crawler.COHERE_TRAINING_DATA_CRAWLER,
|
||||
|
||||
// Common Crawl
|
||||
Crawler.COMMON_CRAWL_CCBOT,
|
||||
|
||||
// Coveo
|
||||
Crawler.COVEO_BOT,
|
||||
|
||||
// DataForSeo
|
||||
Crawler.DATAFORSEO_BOT,
|
||||
|
||||
// DeepSeek
|
||||
Crawler.DEEPSEEK_BOT,
|
||||
|
||||
// Diffbot
|
||||
Crawler.DIFFBOT,
|
||||
|
||||
// Google
|
||||
Crawler.GOOGLE_EXTENDED,
|
||||
Crawler.GOOGLE_OTHER,
|
||||
Crawler.GOOGLE_OTHER_IMAGE,
|
||||
Crawler.GOOGLE_OTHER_VIDEO,
|
||||
Crawler.GOOGLE_CLOUDVERTEXBOT,
|
||||
|
||||
// Hive AI
|
||||
Crawler.HIVE_IMAGESIFTBOT,
|
||||
|
||||
// Huawei
|
||||
Crawler.HUAWEI_PETALBOT,
|
||||
Crawler.HUAWEI_PANGUBOT,
|
||||
|
||||
// Hugging Face
|
||||
Crawler.HUGGINGFACE_BOT,
|
||||
|
||||
// Kangaroo
|
||||
Crawler.KANGAROO_BOT,
|
||||
|
||||
// Mendable.ai
|
||||
Crawler.FIRECRAWL_AGENT,
|
||||
|
||||
// Meta
|
||||
Crawler.META_FACEBOOKBOT,
|
||||
Crawler.META_EXTERNALAGENT,
|
||||
|
||||
// OpenAI
|
||||
Crawler.OPENAI_GPTBOT,
|
||||
Crawler.OPENAI_SEARCH_BOT,
|
||||
|
||||
// Perplexity
|
||||
Crawler.PERPLEXITY_BOT,
|
||||
|
||||
// Replicate
|
||||
Crawler.REPLICATE_BOT,
|
||||
|
||||
// Runpod
|
||||
Crawler.RUNPOD_BOT,
|
||||
|
||||
// SB Intuitions
|
||||
Crawler.SB_INTUITIONS_BOT,
|
||||
|
||||
// Semrush
|
||||
Crawler.SEMRUSH_BOT_CONTENTSHAKE,
|
||||
|
||||
// Timpi
|
||||
Crawler.TIMPI_BOT,
|
||||
|
||||
// Together AI
|
||||
Crawler.TOGETHER_BOT,
|
||||
|
||||
// Velen.io
|
||||
Crawler.HUNTER_VELENPUBLICWEBCRAWLER,
|
||||
|
||||
// Vercel
|
||||
Crawler.VERCEL_V0BOT,
|
||||
|
||||
// Webz.io
|
||||
Crawler.WEBZIO_OMGILI,
|
||||
Crawler.WEBZIO_OMGILI_BOT,
|
||||
Crawler.WEBZIO_EXTENDED,
|
||||
|
||||
// X
|
||||
Crawler.XAI_BOT,
|
||||
|
||||
// You.com
|
||||
Crawler.YOU_BOT,
|
||||
|
||||
// Zhipu AI
|
||||
Crawler.ZHIPU_CHATGLM_SPIDER
|
||||
]);
|
||||
|
||||
const isBot = ua => BotTypes.includes(ua);
|
||||
const isAIAssistant = ua => AIAssistants.includes(ua);
|
||||
const isAICrawler = ua => AICrawlers.includes(ua);
|
||||
|
||||
module.exports = {
|
||||
isAIAssistant,
|
||||
isAICrawler,
|
||||
isBot
|
||||
}
|
||||
@@ -1,192 +0,0 @@
|
||||
// Generated ESM version of ua-parser-js/bot-detection
|
||||
// DO NOT EDIT THIS FILE!
|
||||
// Source: /src/bot-detection/bot-detection.js
|
||||
|
||||
//////////////////////////////////////////////////
|
||||
/* bot-detection submodule of UAParser.js v2.0.7
|
||||
https://github.com/faisalman/ua-parser-js
|
||||
Author: Faisal Salman <f@faisalman.com>
|
||||
AGPLv3 License */
|
||||
/////////////////////////////////////////////////
|
||||
|
||||
/*jshint esversion: 6 */
|
||||
|
||||
import { UAParser } from '../main/ua-parser.mjs';
|
||||
import { Bots, Crawlers, Fetchers } from '../extensions/ua-parser-extensions.mjs';
|
||||
import { BrowserType, Extension } from '../enums/ua-parser-enums.mjs';
|
||||
const { Crawler, Fetcher } = Extension.BrowserName;
|
||||
|
||||
class BotList {
|
||||
constructor(ext, prop, list) {
|
||||
this.ext = ext;
|
||||
this.prop = prop;
|
||||
this.list = list.map(x => x.toLowerCase());
|
||||
}
|
||||
includes(ua) {
|
||||
return this.list.includes(
|
||||
(typeof ua === 'string' ?
|
||||
new UAParser(ua, this.ext).getBrowser() :
|
||||
ua.browser
|
||||
)[this.prop]?.toLowerCase());
|
||||
}
|
||||
}
|
||||
|
||||
const BotTypes = new BotList(Bots, 'type', [
|
||||
BrowserType.CLI,
|
||||
BrowserType.CRAWLER,
|
||||
BrowserType.FETCHER,
|
||||
BrowserType.LIBRARY
|
||||
]);
|
||||
|
||||
const AIAssistants = new BotList(Fetchers, 'name', [
|
||||
|
||||
// Amazon
|
||||
Fetcher.AMAZON_NOVA_ACT,
|
||||
|
||||
// Anthropic
|
||||
Fetcher.ANTHROPIC_CLAUDE_USER,
|
||||
|
||||
// Cohere
|
||||
Fetcher.COHERE_AI,
|
||||
|
||||
// DuckDuckGo
|
||||
Fetcher.DUCKDUCKGO_ASSISTBOT,
|
||||
|
||||
// Google
|
||||
Fetcher.GOOGLE_GEMINI_DEEP_RESEARCH,
|
||||
|
||||
// Mistral AI
|
||||
Fetcher.MISTRALAI_USER,
|
||||
|
||||
// OpenAI
|
||||
Fetcher.OPENAI_CHATGPT_USER,
|
||||
|
||||
// Perplexity
|
||||
Fetcher.PERPLEXITY_USER
|
||||
]);
|
||||
|
||||
const AICrawlers = new BotList(Crawlers, 'name', [
|
||||
|
||||
// AI2
|
||||
Crawler.AI2_BOT,
|
||||
|
||||
// Amazon
|
||||
Crawler.AMAZON_BOT,
|
||||
|
||||
// Anthropic
|
||||
Crawler.ANTHROPIC_AI,
|
||||
Crawler.ANTHROPIC_CLAUDE_BOT,
|
||||
Crawler.ANTHROPIC_CLAUDE_SEARCHBOT,
|
||||
Crawler.ANTHROPIC_CLAUDE_WEB,
|
||||
|
||||
// Apple
|
||||
Crawler.APPLE_BOT,
|
||||
Crawler.APPLE_BOT_EXTENDED,
|
||||
|
||||
// Brave
|
||||
Crawler.BRAVE_BOT,
|
||||
|
||||
// ByteDance
|
||||
Crawler.BYTEDANCE_BYTESPIDER,
|
||||
Crawler.BYTEDANCE_TIKTOKSPIDER,
|
||||
|
||||
// Cohere
|
||||
Crawler.COHERE_TRAINING_DATA_CRAWLER,
|
||||
|
||||
// Common Crawl
|
||||
Crawler.COMMON_CRAWL_CCBOT,
|
||||
|
||||
// Coveo
|
||||
Crawler.COVEO_BOT,
|
||||
|
||||
// DataForSeo
|
||||
Crawler.DATAFORSEO_BOT,
|
||||
|
||||
// DeepSeek
|
||||
Crawler.DEEPSEEK_BOT,
|
||||
|
||||
// Diffbot
|
||||
Crawler.DIFFBOT,
|
||||
|
||||
// Google
|
||||
Crawler.GOOGLE_EXTENDED,
|
||||
Crawler.GOOGLE_OTHER,
|
||||
Crawler.GOOGLE_OTHER_IMAGE,
|
||||
Crawler.GOOGLE_OTHER_VIDEO,
|
||||
Crawler.GOOGLE_CLOUDVERTEXBOT,
|
||||
|
||||
// Hive AI
|
||||
Crawler.HIVE_IMAGESIFTBOT,
|
||||
|
||||
// Huawei
|
||||
Crawler.HUAWEI_PETALBOT,
|
||||
Crawler.HUAWEI_PANGUBOT,
|
||||
|
||||
// Hugging Face
|
||||
Crawler.HUGGINGFACE_BOT,
|
||||
|
||||
// Kangaroo
|
||||
Crawler.KANGAROO_BOT,
|
||||
|
||||
// Mendable.ai
|
||||
Crawler.FIRECRAWL_AGENT,
|
||||
|
||||
// Meta
|
||||
Crawler.META_FACEBOOKBOT,
|
||||
Crawler.META_EXTERNALAGENT,
|
||||
|
||||
// OpenAI
|
||||
Crawler.OPENAI_GPTBOT,
|
||||
Crawler.OPENAI_SEARCH_BOT,
|
||||
|
||||
// Perplexity
|
||||
Crawler.PERPLEXITY_BOT,
|
||||
|
||||
// Replicate
|
||||
Crawler.REPLICATE_BOT,
|
||||
|
||||
// Runpod
|
||||
Crawler.RUNPOD_BOT,
|
||||
|
||||
// SB Intuitions
|
||||
Crawler.SB_INTUITIONS_BOT,
|
||||
|
||||
// Semrush
|
||||
Crawler.SEMRUSH_BOT_CONTENTSHAKE,
|
||||
|
||||
// Timpi
|
||||
Crawler.TIMPI_BOT,
|
||||
|
||||
// Together AI
|
||||
Crawler.TOGETHER_BOT,
|
||||
|
||||
// Velen.io
|
||||
Crawler.HUNTER_VELENPUBLICWEBCRAWLER,
|
||||
|
||||
// Vercel
|
||||
Crawler.VERCEL_V0BOT,
|
||||
|
||||
// Webz.io
|
||||
Crawler.WEBZIO_OMGILI,
|
||||
Crawler.WEBZIO_OMGILI_BOT,
|
||||
Crawler.WEBZIO_EXTENDED,
|
||||
|
||||
// X
|
||||
Crawler.XAI_BOT,
|
||||
|
||||
// You.com
|
||||
Crawler.YOU_BOT,
|
||||
|
||||
// Zhipu AI
|
||||
Crawler.ZHIPU_CHATGLM_SPIDER
|
||||
]);
|
||||
|
||||
const isBot = ua => BotTypes.includes(ua);
|
||||
const isAIAssistant = ua => AIAssistants.includes(ua);
|
||||
const isAICrawler = ua => AICrawlers.includes(ua);
|
||||
|
||||
export {
|
||||
isAIAssistant,
|
||||
isAICrawler,
|
||||
isBot
|
||||
}
|
||||
10
src/browser-detection/browser-detection.d.ts
vendored
10
src/browser-detection/browser-detection.d.ts
vendored
@@ -1,10 +0,0 @@
|
||||
// Type definitions for browser-detection submodule of UAParser.js v2.0.7
|
||||
// Project: https://github.com/faisalman/ua-parser-js
|
||||
// Definitions by: Faisal Salman <https://github.com/faisalman>
|
||||
|
||||
import type { IResult } from "../main/ua-parser";
|
||||
|
||||
export function isChromeFamily(resultOrUA: IResult | string): boolean;
|
||||
export function isElectron(): boolean;
|
||||
export function isFromEU(): boolean;
|
||||
export function isStandalonePWA(): boolean;
|
||||
@@ -1,30 +0,0 @@
|
||||
//////////////////////////////////////////////////////
|
||||
/* browser-detection submodule of UAParser.js v2.0.7
|
||||
https://github.com/faisalman/ua-parser-js
|
||||
Author: Faisal Salman <f@faisalman.com>
|
||||
AGPLv3 License */
|
||||
/////////////////////////////////////////////////////
|
||||
|
||||
/*jshint esversion: 6 */
|
||||
|
||||
const { UAParser } = require('../main/ua-parser');
|
||||
const { EngineName } = require('../enums/ua-parser-enums');
|
||||
const { isStandalonePWA } = require('is-standalone-pwa');
|
||||
const { isFromEU } = require('detect-europe-js');
|
||||
|
||||
const isChromeFamily = val => !!(
|
||||
(typeof val === 'string' ?
|
||||
new UAParser(val).getEngine() :
|
||||
val.engine
|
||||
)?.is(EngineName.BLINK));
|
||||
|
||||
const isElectron = () => !!(
|
||||
process?.versions?.hasOwnProperty('electron') || // node.js
|
||||
/ electron\//i.test(navigator?.userAgent)); // browser
|
||||
|
||||
module.exports = {
|
||||
isChromeFamily,
|
||||
isElectron,
|
||||
isFromEU,
|
||||
isStandalonePWA
|
||||
}
|
||||
@@ -1,34 +0,0 @@
|
||||
// Generated ESM version of ua-parser-js/browser-detection
|
||||
// DO NOT EDIT THIS FILE!
|
||||
// Source: /src/browser-detection/browser-detection.js
|
||||
|
||||
//////////////////////////////////////////////////////
|
||||
/* browser-detection submodule of UAParser.js v2.0.7
|
||||
https://github.com/faisalman/ua-parser-js
|
||||
Author: Faisal Salman <f@faisalman.com>
|
||||
AGPLv3 License */
|
||||
/////////////////////////////////////////////////////
|
||||
|
||||
/*jshint esversion: 6 */
|
||||
|
||||
import { UAParser } from '../main/ua-parser.mjs';
|
||||
import { EngineName } from '../enums/ua-parser-enums.mjs';
|
||||
import { isStandalonePWA } from 'is-standalone-pwa';
|
||||
import { isFromEU } from 'detect-europe-js';
|
||||
|
||||
const isChromeFamily = val => !!(
|
||||
(typeof val === 'string' ?
|
||||
new UAParser(val).getEngine() :
|
||||
val.engine
|
||||
)?.is(EngineName.BLINK));
|
||||
|
||||
const isElectron = () => !!(
|
||||
process?.versions?.hasOwnProperty('electron') || // node.js
|
||||
/ electron\//i.test(navigator?.userAgent)); // browser
|
||||
|
||||
export {
|
||||
isChromeFamily,
|
||||
isElectron,
|
||||
isFromEU,
|
||||
isStandalonePWA
|
||||
}
|
||||
8
src/device-detection/device-detection.d.ts
vendored
8
src/device-detection/device-detection.d.ts
vendored
@@ -1,8 +0,0 @@
|
||||
// Type definitions for device-detection submodule of UAParser.js v2.0.7
|
||||
// Project: https://github.com/faisalman/ua-parser-js
|
||||
// Definitions by: Faisal Salman <https://github.com/faisalman>
|
||||
|
||||
import type { IResult } from "../main/ua-parser";
|
||||
|
||||
export function getDeviceVendor(model: string): string | undefined;
|
||||
export function isAppleSilicon(resultOrUA: IResult | string): boolean;
|
||||
@@ -1,43 +0,0 @@
|
||||
/////////////////////////////////////////////////////
|
||||
/* device-detection submodule of UAParser.js v2.0.7
|
||||
https://github.com/faisalman/ua-parser-js
|
||||
Author: Faisal Salman <f@faisalman.com>
|
||||
AGPLv3 License */
|
||||
////////////////////////////////////////////////////
|
||||
|
||||
/*jshint esversion: 6 */
|
||||
|
||||
const { UAParser } = require('../main/ua-parser');
|
||||
const { CPUArch, OSName } = require('../enums/ua-parser-enums');
|
||||
|
||||
const getDeviceVendor = (model) => new UAParser(`Mozilla/5.0 (Linux; Android 10; ${model}) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/100.0.0.0 Safari/537.36`).getDevice().vendor;
|
||||
|
||||
const isAppleSilicon = (val) => {
|
||||
const { os, cpu } = typeof val !== 'string' ? val : {
|
||||
os: new UAParser(val).getOS(),
|
||||
cpu: new UAParser(val).getCPU()
|
||||
};
|
||||
if (os.is(OSName.MACOS)) {
|
||||
if (cpu.is(CPUArch.ARM)) {
|
||||
return true;
|
||||
} else if (typeof window !== 'undefined') {
|
||||
try {
|
||||
const canvas = document.createElement('canvas');
|
||||
const webgl = canvas.getContext('webgl2') ||
|
||||
canvas.getContext('webgl') ||
|
||||
canvas.getContext('experimental-webgl');
|
||||
return webgl
|
||||
.getParameter(webgl.getExtension('WEBGL_debug_renderer_info').UNMASKED_RENDERER_WEBGL)
|
||||
.match(/apple m\d/i);
|
||||
} catch {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
module.exports = {
|
||||
getDeviceVendor,
|
||||
isAppleSilicon
|
||||
}
|
||||
@@ -1,47 +0,0 @@
|
||||
// Generated ESM version of ua-parser-js/device-detection
|
||||
// DO NOT EDIT THIS FILE!
|
||||
// Source: /src/device-detection/device-detection.js
|
||||
|
||||
/////////////////////////////////////////////////////
|
||||
/* device-detection submodule of UAParser.js v2.0.7
|
||||
https://github.com/faisalman/ua-parser-js
|
||||
Author: Faisal Salman <f@faisalman.com>
|
||||
AGPLv3 License */
|
||||
////////////////////////////////////////////////////
|
||||
|
||||
/*jshint esversion: 6 */
|
||||
|
||||
import { UAParser } from '../main/ua-parser.mjs';
|
||||
import { CPUArch, OSName } from '../enums/ua-parser-enums.mjs';
|
||||
|
||||
const getDeviceVendor = (model) => new UAParser(`Mozilla/5.0 (Linux; Android 10; ${model}) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/100.0.0.0 Safari/537.36`).getDevice().vendor;
|
||||
|
||||
const isAppleSilicon = (val) => {
|
||||
const { os, cpu } = typeof val !== 'string' ? val : {
|
||||
os: new UAParser(val).getOS(),
|
||||
cpu: new UAParser(val).getCPU()
|
||||
};
|
||||
if (os.is(OSName.MACOS)) {
|
||||
if (cpu.is(CPUArch.ARM)) {
|
||||
return true;
|
||||
} else if (typeof window !== 'undefined') {
|
||||
try {
|
||||
const canvas = document.createElement('canvas');
|
||||
const webgl = canvas.getContext('webgl2') ||
|
||||
canvas.getContext('webgl') ||
|
||||
canvas.getContext('experimental-webgl');
|
||||
return webgl
|
||||
.getParameter(webgl.getExtension('WEBGL_debug_renderer_info').UNMASKED_RENDERER_WEBGL)
|
||||
.match(/apple m\d/i);
|
||||
} catch {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
export {
|
||||
getDeviceVendor,
|
||||
isAppleSilicon
|
||||
}
|
||||
38
src/enums/ua-parser-enums.d.ts
vendored
38
src/enums/ua-parser-enums.d.ts
vendored
@@ -3,10 +3,10 @@
|
||||
// Source: /src/enums/ua-parser-enums.js
|
||||
|
||||
///////////////////////////////////////////////
|
||||
/* Enums for UAParser.js v2.0.7
|
||||
/* Enums for UAParser.js v2.0.5
|
||||
https://github.com/faisalman/ua-parser-js
|
||||
Author: Faisal Salman <f@faisalman.com>
|
||||
AGPLv3 License */
|
||||
UAParser.js PRO Personal License */
|
||||
//////////////////////////////////////////////
|
||||
|
||||
/*jshint esversion: 6 */
|
||||
@@ -19,13 +19,11 @@ export const BrowserName: Readonly<{
|
||||
AMAYA: 'Amaya',
|
||||
ANDROID: 'Android Browser',
|
||||
ARORA: 'Arora',
|
||||
ATLAS: 'Atlas',
|
||||
AVANT: 'Avant',
|
||||
AVAST: 'Avast Secure Browser',
|
||||
AVG: 'AVG Secure Browser',
|
||||
BAIDU: 'Baidu Browser',
|
||||
BASILISK: 'Basilisk',
|
||||
BING: 'Bing',
|
||||
BLAZER: 'Blazer',
|
||||
BOLT: 'Bolt',
|
||||
BOWSER: 'Bowser',
|
||||
@@ -131,7 +129,6 @@ export const BrowserName: Readonly<{
|
||||
QUARK: 'Quark',
|
||||
QUPZILLA: 'QupZilla',
|
||||
QUTEBROWSER: 'qutebrowser',
|
||||
QWANT: 'Qwant',
|
||||
REKONQ: 'rekonq',
|
||||
ROCKMELT: 'Rockmelt',
|
||||
SAFARI: 'Safari',
|
||||
@@ -148,7 +145,6 @@ export const BrowserName: Readonly<{
|
||||
SNAPCHAT: 'Snapchat',
|
||||
SOGOU_EXPLORER: 'Sogou Explorer',
|
||||
SOGOU_MOBILE: 'Sogou Mobile',
|
||||
STEAM: 'Steam',
|
||||
SURF: 'Surf',
|
||||
SWIFTFOX: 'Swiftfox',
|
||||
TESLA: 'Tesla',
|
||||
@@ -230,9 +226,8 @@ export const DeviceVendor: Readonly<{
|
||||
ACER: 'Acer',
|
||||
ADVAN: 'Advan',
|
||||
ALCATEL: 'Alcatel',
|
||||
AMAZON: 'Amazon',
|
||||
ANBERNIC: 'Anbernic',
|
||||
APPLE: 'Apple',
|
||||
AMAZON: 'Amazon',
|
||||
ARCHOS: 'Archos',
|
||||
ASUS: 'ASUS',
|
||||
ATT: 'AT&T',
|
||||
@@ -248,7 +243,6 @@ export const DeviceVendor: Readonly<{
|
||||
GEEKSPHONE: 'GeeksPhone',
|
||||
GENERIC: 'Generic',
|
||||
GOOGLE: 'Google',
|
||||
HISENSE: 'Hisense',
|
||||
HMD: 'HMD',
|
||||
HP: 'HP',
|
||||
HTC: 'HTC',
|
||||
@@ -261,7 +255,6 @@ export const DeviceVendor: Readonly<{
|
||||
LAVA: 'Lava',
|
||||
LENOVO: 'Lenovo',
|
||||
LG: 'LG',
|
||||
LOGITECH: 'Logitech',
|
||||
MEIZU: 'Meizu',
|
||||
MICROMAX: 'Micromax',
|
||||
MICROSOFT: 'Microsoft',
|
||||
@@ -295,11 +288,9 @@ export const DeviceVendor: Readonly<{
|
||||
TECNO: 'TECNO',
|
||||
TESLA: 'Tesla',
|
||||
ULEFONE: 'Ulefone',
|
||||
VALVE: 'Valve',
|
||||
VIVO: 'Vivo',
|
||||
VIZIO: 'Vizio',
|
||||
VODAFONE: 'Vodafone',
|
||||
WIKO: 'Wiko',
|
||||
XBOX: 'Xbox',
|
||||
XIAOMI: 'Xiaomi',
|
||||
ZEBRA: 'Zebra',
|
||||
@@ -498,7 +489,6 @@ export const Extension: Readonly<{
|
||||
DUCKDUCKGO_BOT: 'DuckDuckBot',
|
||||
DUCKDUCKGO_FAVICONS_BOT: 'DuckDuckGo-Favicons-Bot',
|
||||
ELASTIC: 'Elastic',
|
||||
ELASTIC_SWIFTYPE_BOT: 'Swiftbot',
|
||||
EXALEAD_EXABOT: 'Exabot',
|
||||
FIRECRAWL_AGENT: 'FirecrawlAgent',
|
||||
FREESPOKE: 'Freespoke',
|
||||
@@ -548,7 +538,6 @@ export const Extension: Readonly<{
|
||||
PERPLEXITY_BOT: 'PerplexityBot',
|
||||
QIHOO_360_SPIDER: '360Spider',
|
||||
QWANT_BOT: 'Qwantbot',
|
||||
QWANT_BOT_NEWS: 'Qwantbot-news',
|
||||
REPLICATE_BOT: 'Replicate-Bot',
|
||||
RUNPOD_BOT: 'RunPod-Bot',
|
||||
SB_INTUITIONS_BOT: 'SBIntuitionsBot',
|
||||
@@ -562,7 +551,6 @@ export const Extension: Readonly<{
|
||||
SOGOU_PIC_SPIDER: 'Sogou Pic Spider',
|
||||
SOGOU_WEB_SPIDER: 'Sogou web spider',
|
||||
STARTPAGE: 'Startpage',
|
||||
SURLY_BOT: 'SurdotlyBot',
|
||||
TIMPI_BOT: 'Timpibot',
|
||||
TOGETHER_BOT: 'Together-Bot',
|
||||
TURNITIN_BOT: 'TurnitinBot',
|
||||
@@ -636,7 +624,6 @@ export const Extension: Readonly<{
|
||||
},
|
||||
Fetcher: {
|
||||
AHREFS_SITEAUDIT: 'AhrefsSiteAudit',
|
||||
AMAZON_NOVA_ACT: 'NovaAct',
|
||||
ANTHROPIC_CLAUDE_USER: 'Claude-User',
|
||||
ASANA: 'Asana',
|
||||
BETTER_UPTIME_BOT: 'Better Uptime Bot',
|
||||
@@ -644,7 +631,6 @@ export const Extension: Readonly<{
|
||||
BLUESKY: 'Bluesky',
|
||||
BUFFER_LINKPREVIEWBOT: 'BufferLinkPreviewBot',
|
||||
COHERE_AI: 'Cohere-AI',
|
||||
DISCORD_BOT: 'Discordbot',
|
||||
DUCKDUCKGO_ASSISTBOT: 'DuckAssistBot',
|
||||
GOOGLE_CHROME_LIGHTHOUSE: 'Chrome-Lighthouse',
|
||||
GOOGLE_FEEDFETCHER: 'FeedFetcher-Google',
|
||||
@@ -657,7 +643,6 @@ export const Extension: Readonly<{
|
||||
HUBSPOT_PAGE_FETCHER: 'HubSpot Page Fetcher',
|
||||
IFRAMELY: 'Iframely',
|
||||
KAKAOTALK_SCRAP: 'kakaotalk-scrap',
|
||||
KEYBASE_BOT: 'KeybaseBot',
|
||||
META_EXTERNALFETCHER: 'meta-externalfetcher',
|
||||
META_WHATSAPP: 'WhatsApp',
|
||||
MICROSOFT_BINGPREVIEW: 'BingPreview',
|
||||
@@ -669,9 +654,6 @@ export const Extension: Readonly<{
|
||||
PERPLEXITY_USER: 'Perplexity-User',
|
||||
PINTEREST_BOT: 'Pinterestbot',
|
||||
SEMRUSH_SITEAUDITBOT: 'SiteAuditBot',
|
||||
SLACK_BOT: 'Slackbot',
|
||||
SLACK_BOT_LINKEXPANDING: 'Slackbot-LinkExpanding',
|
||||
SLACK_IMGPROXY: 'Slack-ImgProxy',
|
||||
SNAP_URL_PREVIEW: 'Snap URL Preview',
|
||||
SKYPE_URIPREVIEW: 'SkypeUriPreview',
|
||||
TELEGRAM_BOT: 'TelegramBot',
|
||||
@@ -681,7 +663,6 @@ export const Extension: Readonly<{
|
||||
VERCEL_BOT: 'Vercelbot',
|
||||
VERCEL_FLAGS: 'vercelflags',
|
||||
VERCEL_TRACING: 'verceltracing',
|
||||
X_TWITTERBOT: 'Twitterbot',
|
||||
YANDEX_CALENDAR: 'YandexCalendar',
|
||||
YANDEX_DIRECT: 'YandexDirect',
|
||||
YANDEX_DIRECTDYN: 'YandexDirectDyn',
|
||||
@@ -714,13 +695,9 @@ export const Extension: Readonly<{
|
||||
AIOHTTP: 'aiohttp',
|
||||
APACHE_HTTPCLIENT: 'Apache-HttpClient',
|
||||
AXIOS: 'axios',
|
||||
BUN: 'Bun',
|
||||
DART: 'Dart',
|
||||
DENO: 'Deno',
|
||||
GO_HTTP_CLIENT: 'go-http-client',
|
||||
GOT: 'got',
|
||||
GUZZLEHTTP: 'GuzzleHttp',
|
||||
HACKNEY: 'hackney',
|
||||
JAVA: 'Java',
|
||||
JAVA_HTTPCLIENT: 'Java-http-client',
|
||||
JSDOM: 'jsdom',
|
||||
@@ -728,19 +705,16 @@ export const Extension: Readonly<{
|
||||
LUA_RESTY_HTTP: 'lua-resty-http',
|
||||
NEEDLE: 'Needle',
|
||||
NUTCH: 'Nutch',
|
||||
NODE_FETCH: 'node-fetch',
|
||||
NODE_JS: 'Node.js',
|
||||
NODE_SUPERAGENT: 'node-superagent',
|
||||
OKHTTP: 'OkHttp',
|
||||
NODE_FETCH: 'node-fetch',
|
||||
NODE_SUPERAGENT: 'node-superagent',
|
||||
PHP_SOAP: 'PHP-SOAP',
|
||||
POSTMAN_RUNTIME: 'PostmanRuntime',
|
||||
PYTHON_HTTPX: 'python-httpx',
|
||||
PYTHON_URLLIB: 'python-urllib',
|
||||
PYTHON_URLLIB3: 'python-urllib3',
|
||||
PYTHON_REQUESTS: 'python-requests',
|
||||
REST_CLIENT: 'rest-client',
|
||||
SCRAPY: 'Scrapy',
|
||||
UNDICI: 'undici'
|
||||
SCRAPY: 'Scrapy'
|
||||
}
|
||||
},
|
||||
DeviceVendor: {
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
///////////////////////////////////////////////
|
||||
/* Enums for UAParser.js v2.0.7
|
||||
/* Enums for UAParser.js v2.0.5
|
||||
https://github.com/faisalman/ua-parser-js
|
||||
Author: Faisal Salman <f@faisalman.com>
|
||||
AGPLv3 License */
|
||||
UAParser.js PRO Personal License */
|
||||
//////////////////////////////////////////////
|
||||
|
||||
/*jshint esversion: 6 */
|
||||
@@ -15,13 +15,11 @@ const BrowserName = Object.freeze({
|
||||
AMAYA: 'Amaya',
|
||||
ANDROID: 'Android Browser',
|
||||
ARORA: 'Arora',
|
||||
ATLAS: 'Atlas',
|
||||
AVANT: 'Avant',
|
||||
AVAST: 'Avast Secure Browser',
|
||||
AVG: 'AVG Secure Browser',
|
||||
BAIDU: 'Baidu Browser',
|
||||
BASILISK: 'Basilisk',
|
||||
BING: 'Bing',
|
||||
BLAZER: 'Blazer',
|
||||
BOLT: 'Bolt',
|
||||
BOWSER: 'Bowser',
|
||||
@@ -127,7 +125,6 @@ const BrowserName = Object.freeze({
|
||||
QUARK: 'Quark',
|
||||
QUPZILLA: 'QupZilla',
|
||||
QUTEBROWSER: 'qutebrowser',
|
||||
QWANT: 'Qwant',
|
||||
REKONQ: 'rekonq',
|
||||
ROCKMELT: 'Rockmelt',
|
||||
SAFARI: 'Safari',
|
||||
@@ -144,7 +141,6 @@ const BrowserName = Object.freeze({
|
||||
SNAPCHAT: 'Snapchat',
|
||||
SOGOU_EXPLORER: 'Sogou Explorer',
|
||||
SOGOU_MOBILE: 'Sogou Mobile',
|
||||
STEAM: 'Steam',
|
||||
SURF: 'Surf',
|
||||
SWIFTFOX: 'Swiftfox',
|
||||
TESLA: 'Tesla',
|
||||
@@ -226,9 +222,8 @@ const DeviceVendor = Object.freeze({
|
||||
ACER: 'Acer',
|
||||
ADVAN: 'Advan',
|
||||
ALCATEL: 'Alcatel',
|
||||
AMAZON: 'Amazon',
|
||||
ANBERNIC: 'Anbernic',
|
||||
APPLE: 'Apple',
|
||||
AMAZON: 'Amazon',
|
||||
ARCHOS: 'Archos',
|
||||
ASUS: 'ASUS',
|
||||
ATT: 'AT&T',
|
||||
@@ -244,7 +239,6 @@ const DeviceVendor = Object.freeze({
|
||||
GEEKSPHONE: 'GeeksPhone',
|
||||
GENERIC: 'Generic',
|
||||
GOOGLE: 'Google',
|
||||
HISENSE: 'Hisense',
|
||||
HMD: 'HMD',
|
||||
HP: 'HP',
|
||||
HTC: 'HTC',
|
||||
@@ -257,7 +251,6 @@ const DeviceVendor = Object.freeze({
|
||||
LAVA: 'Lava',
|
||||
LENOVO: 'Lenovo',
|
||||
LG: 'LG',
|
||||
LOGITECH: 'Logitech',
|
||||
MEIZU: 'Meizu',
|
||||
MICROMAX: 'Micromax',
|
||||
MICROSOFT: 'Microsoft',
|
||||
@@ -291,11 +284,9 @@ const DeviceVendor = Object.freeze({
|
||||
TECNO: 'TECNO',
|
||||
TESLA: 'Tesla',
|
||||
ULEFONE: 'Ulefone',
|
||||
VALVE: 'Valve',
|
||||
VIVO: 'Vivo',
|
||||
VIZIO: 'Vizio',
|
||||
VODAFONE: 'Vodafone',
|
||||
WIKO: 'Wiko',
|
||||
XBOX: 'Xbox',
|
||||
XIAOMI: 'Xiaomi',
|
||||
ZEBRA: 'Zebra',
|
||||
@@ -494,7 +485,6 @@ const Extension = Object.freeze({
|
||||
DUCKDUCKGO_BOT: 'DuckDuckBot',
|
||||
DUCKDUCKGO_FAVICONS_BOT: 'DuckDuckGo-Favicons-Bot',
|
||||
ELASTIC: 'Elastic',
|
||||
ELASTIC_SWIFTYPE_BOT: 'Swiftbot',
|
||||
EXALEAD_EXABOT: 'Exabot',
|
||||
FIRECRAWL_AGENT: 'FirecrawlAgent',
|
||||
FREESPOKE: 'Freespoke',
|
||||
@@ -544,7 +534,6 @@ const Extension = Object.freeze({
|
||||
PERPLEXITY_BOT: 'PerplexityBot',
|
||||
QIHOO_360_SPIDER: '360Spider',
|
||||
QWANT_BOT: 'Qwantbot',
|
||||
QWANT_BOT_NEWS: 'Qwantbot-news',
|
||||
REPLICATE_BOT: 'Replicate-Bot',
|
||||
RUNPOD_BOT: 'RunPod-Bot',
|
||||
SB_INTUITIONS_BOT: 'SBIntuitionsBot',
|
||||
@@ -558,7 +547,6 @@ const Extension = Object.freeze({
|
||||
SOGOU_PIC_SPIDER: 'Sogou Pic Spider',
|
||||
SOGOU_WEB_SPIDER: 'Sogou web spider',
|
||||
STARTPAGE: 'Startpage',
|
||||
SURLY_BOT: 'SurdotlyBot',
|
||||
TIMPI_BOT: 'Timpibot',
|
||||
TOGETHER_BOT: 'Together-Bot',
|
||||
TURNITIN_BOT: 'TurnitinBot',
|
||||
@@ -632,7 +620,6 @@ const Extension = Object.freeze({
|
||||
},
|
||||
Fetcher: {
|
||||
AHREFS_SITEAUDIT: 'AhrefsSiteAudit',
|
||||
AMAZON_NOVA_ACT: 'NovaAct',
|
||||
ANTHROPIC_CLAUDE_USER: 'Claude-User',
|
||||
ASANA: 'Asana',
|
||||
BETTER_UPTIME_BOT: 'Better Uptime Bot',
|
||||
@@ -640,7 +627,6 @@ const Extension = Object.freeze({
|
||||
BLUESKY: 'Bluesky',
|
||||
BUFFER_LINKPREVIEWBOT: 'BufferLinkPreviewBot',
|
||||
COHERE_AI: 'Cohere-AI',
|
||||
DISCORD_BOT: 'Discordbot',
|
||||
DUCKDUCKGO_ASSISTBOT: 'DuckAssistBot',
|
||||
GOOGLE_CHROME_LIGHTHOUSE: 'Chrome-Lighthouse',
|
||||
GOOGLE_FEEDFETCHER: 'FeedFetcher-Google',
|
||||
@@ -653,7 +639,6 @@ const Extension = Object.freeze({
|
||||
HUBSPOT_PAGE_FETCHER: 'HubSpot Page Fetcher',
|
||||
IFRAMELY: 'Iframely',
|
||||
KAKAOTALK_SCRAP: 'kakaotalk-scrap',
|
||||
KEYBASE_BOT: 'KeybaseBot',
|
||||
META_EXTERNALFETCHER: 'meta-externalfetcher',
|
||||
META_WHATSAPP: 'WhatsApp',
|
||||
MICROSOFT_BINGPREVIEW: 'BingPreview',
|
||||
@@ -665,9 +650,6 @@ const Extension = Object.freeze({
|
||||
PERPLEXITY_USER: 'Perplexity-User',
|
||||
PINTEREST_BOT: 'Pinterestbot',
|
||||
SEMRUSH_SITEAUDITBOT: 'SiteAuditBot',
|
||||
SLACK_BOT: 'Slackbot',
|
||||
SLACK_BOT_LINKEXPANDING: 'Slackbot-LinkExpanding',
|
||||
SLACK_IMGPROXY: 'Slack-ImgProxy',
|
||||
SNAP_URL_PREVIEW: 'Snap URL Preview',
|
||||
SKYPE_URIPREVIEW: 'SkypeUriPreview',
|
||||
TELEGRAM_BOT: 'TelegramBot',
|
||||
@@ -677,7 +659,6 @@ const Extension = Object.freeze({
|
||||
VERCEL_BOT: 'Vercelbot',
|
||||
VERCEL_FLAGS: 'vercelflags',
|
||||
VERCEL_TRACING: 'verceltracing',
|
||||
X_TWITTERBOT: 'Twitterbot',
|
||||
YANDEX_CALENDAR: 'YandexCalendar',
|
||||
YANDEX_DIRECT: 'YandexDirect',
|
||||
YANDEX_DIRECTDYN: 'YandexDirectDyn',
|
||||
@@ -710,13 +691,9 @@ const Extension = Object.freeze({
|
||||
AIOHTTP: 'aiohttp',
|
||||
APACHE_HTTPCLIENT: 'Apache-HttpClient',
|
||||
AXIOS: 'axios',
|
||||
BUN: 'Bun',
|
||||
DART: 'Dart',
|
||||
DENO: 'Deno',
|
||||
GO_HTTP_CLIENT: 'go-http-client',
|
||||
GOT: 'got',
|
||||
GUZZLEHTTP: 'GuzzleHttp',
|
||||
HACKNEY: 'hackney',
|
||||
JAVA: 'Java',
|
||||
JAVA_HTTPCLIENT: 'Java-http-client',
|
||||
JSDOM: 'jsdom',
|
||||
@@ -724,19 +701,16 @@ const Extension = Object.freeze({
|
||||
LUA_RESTY_HTTP: 'lua-resty-http',
|
||||
NEEDLE: 'Needle',
|
||||
NUTCH: 'Nutch',
|
||||
NODE_FETCH: 'node-fetch',
|
||||
NODE_JS: 'Node.js',
|
||||
NODE_SUPERAGENT: 'node-superagent',
|
||||
OKHTTP: 'OkHttp',
|
||||
NODE_FETCH: 'node-fetch',
|
||||
NODE_SUPERAGENT: 'node-superagent',
|
||||
PHP_SOAP: 'PHP-SOAP',
|
||||
POSTMAN_RUNTIME: 'PostmanRuntime',
|
||||
PYTHON_HTTPX: 'python-httpx',
|
||||
PYTHON_URLLIB: 'python-urllib',
|
||||
PYTHON_URLLIB3: 'python-urllib3',
|
||||
PYTHON_REQUESTS: 'python-requests',
|
||||
REST_CLIENT: 'rest-client',
|
||||
SCRAPY: 'Scrapy',
|
||||
UNDICI: 'undici'
|
||||
SCRAPY: 'Scrapy'
|
||||
}
|
||||
},
|
||||
DeviceVendor: {
|
||||
|
||||
@@ -3,10 +3,10 @@
|
||||
// Source: /src/enums/ua-parser-enums.js
|
||||
|
||||
///////////////////////////////////////////////
|
||||
/* Enums for UAParser.js v2.0.7
|
||||
/* Enums for UAParser.js v2.0.5
|
||||
https://github.com/faisalman/ua-parser-js
|
||||
Author: Faisal Salman <f@faisalman.com>
|
||||
AGPLv3 License */
|
||||
UAParser.js PRO Personal License */
|
||||
//////////////////////////////////////////////
|
||||
|
||||
/*jshint esversion: 6 */
|
||||
@@ -19,13 +19,11 @@ const BrowserName = Object.freeze({
|
||||
AMAYA: 'Amaya',
|
||||
ANDROID: 'Android Browser',
|
||||
ARORA: 'Arora',
|
||||
ATLAS: 'Atlas',
|
||||
AVANT: 'Avant',
|
||||
AVAST: 'Avast Secure Browser',
|
||||
AVG: 'AVG Secure Browser',
|
||||
BAIDU: 'Baidu Browser',
|
||||
BASILISK: 'Basilisk',
|
||||
BING: 'Bing',
|
||||
BLAZER: 'Blazer',
|
||||
BOLT: 'Bolt',
|
||||
BOWSER: 'Bowser',
|
||||
@@ -131,7 +129,6 @@ const BrowserName = Object.freeze({
|
||||
QUARK: 'Quark',
|
||||
QUPZILLA: 'QupZilla',
|
||||
QUTEBROWSER: 'qutebrowser',
|
||||
QWANT: 'Qwant',
|
||||
REKONQ: 'rekonq',
|
||||
ROCKMELT: 'Rockmelt',
|
||||
SAFARI: 'Safari',
|
||||
@@ -148,7 +145,6 @@ const BrowserName = Object.freeze({
|
||||
SNAPCHAT: 'Snapchat',
|
||||
SOGOU_EXPLORER: 'Sogou Explorer',
|
||||
SOGOU_MOBILE: 'Sogou Mobile',
|
||||
STEAM: 'Steam',
|
||||
SURF: 'Surf',
|
||||
SWIFTFOX: 'Swiftfox',
|
||||
TESLA: 'Tesla',
|
||||
@@ -230,9 +226,8 @@ const DeviceVendor = Object.freeze({
|
||||
ACER: 'Acer',
|
||||
ADVAN: 'Advan',
|
||||
ALCATEL: 'Alcatel',
|
||||
AMAZON: 'Amazon',
|
||||
ANBERNIC: 'Anbernic',
|
||||
APPLE: 'Apple',
|
||||
AMAZON: 'Amazon',
|
||||
ARCHOS: 'Archos',
|
||||
ASUS: 'ASUS',
|
||||
ATT: 'AT&T',
|
||||
@@ -248,7 +243,6 @@ const DeviceVendor = Object.freeze({
|
||||
GEEKSPHONE: 'GeeksPhone',
|
||||
GENERIC: 'Generic',
|
||||
GOOGLE: 'Google',
|
||||
HISENSE: 'Hisense',
|
||||
HMD: 'HMD',
|
||||
HP: 'HP',
|
||||
HTC: 'HTC',
|
||||
@@ -261,7 +255,6 @@ const DeviceVendor = Object.freeze({
|
||||
LAVA: 'Lava',
|
||||
LENOVO: 'Lenovo',
|
||||
LG: 'LG',
|
||||
LOGITECH: 'Logitech',
|
||||
MEIZU: 'Meizu',
|
||||
MICROMAX: 'Micromax',
|
||||
MICROSOFT: 'Microsoft',
|
||||
@@ -295,11 +288,9 @@ const DeviceVendor = Object.freeze({
|
||||
TECNO: 'TECNO',
|
||||
TESLA: 'Tesla',
|
||||
ULEFONE: 'Ulefone',
|
||||
VALVE: 'Valve',
|
||||
VIVO: 'Vivo',
|
||||
VIZIO: 'Vizio',
|
||||
VODAFONE: 'Vodafone',
|
||||
WIKO: 'Wiko',
|
||||
XBOX: 'Xbox',
|
||||
XIAOMI: 'Xiaomi',
|
||||
ZEBRA: 'Zebra',
|
||||
@@ -498,7 +489,6 @@ const Extension = Object.freeze({
|
||||
DUCKDUCKGO_BOT: 'DuckDuckBot',
|
||||
DUCKDUCKGO_FAVICONS_BOT: 'DuckDuckGo-Favicons-Bot',
|
||||
ELASTIC: 'Elastic',
|
||||
ELASTIC_SWIFTYPE_BOT: 'Swiftbot',
|
||||
EXALEAD_EXABOT: 'Exabot',
|
||||
FIRECRAWL_AGENT: 'FirecrawlAgent',
|
||||
FREESPOKE: 'Freespoke',
|
||||
@@ -548,7 +538,6 @@ const Extension = Object.freeze({
|
||||
PERPLEXITY_BOT: 'PerplexityBot',
|
||||
QIHOO_360_SPIDER: '360Spider',
|
||||
QWANT_BOT: 'Qwantbot',
|
||||
QWANT_BOT_NEWS: 'Qwantbot-news',
|
||||
REPLICATE_BOT: 'Replicate-Bot',
|
||||
RUNPOD_BOT: 'RunPod-Bot',
|
||||
SB_INTUITIONS_BOT: 'SBIntuitionsBot',
|
||||
@@ -562,7 +551,6 @@ const Extension = Object.freeze({
|
||||
SOGOU_PIC_SPIDER: 'Sogou Pic Spider',
|
||||
SOGOU_WEB_SPIDER: 'Sogou web spider',
|
||||
STARTPAGE: 'Startpage',
|
||||
SURLY_BOT: 'SurdotlyBot',
|
||||
TIMPI_BOT: 'Timpibot',
|
||||
TOGETHER_BOT: 'Together-Bot',
|
||||
TURNITIN_BOT: 'TurnitinBot',
|
||||
@@ -636,7 +624,6 @@ const Extension = Object.freeze({
|
||||
},
|
||||
Fetcher: {
|
||||
AHREFS_SITEAUDIT: 'AhrefsSiteAudit',
|
||||
AMAZON_NOVA_ACT: 'NovaAct',
|
||||
ANTHROPIC_CLAUDE_USER: 'Claude-User',
|
||||
ASANA: 'Asana',
|
||||
BETTER_UPTIME_BOT: 'Better Uptime Bot',
|
||||
@@ -644,7 +631,6 @@ const Extension = Object.freeze({
|
||||
BLUESKY: 'Bluesky',
|
||||
BUFFER_LINKPREVIEWBOT: 'BufferLinkPreviewBot',
|
||||
COHERE_AI: 'Cohere-AI',
|
||||
DISCORD_BOT: 'Discordbot',
|
||||
DUCKDUCKGO_ASSISTBOT: 'DuckAssistBot',
|
||||
GOOGLE_CHROME_LIGHTHOUSE: 'Chrome-Lighthouse',
|
||||
GOOGLE_FEEDFETCHER: 'FeedFetcher-Google',
|
||||
@@ -657,7 +643,6 @@ const Extension = Object.freeze({
|
||||
HUBSPOT_PAGE_FETCHER: 'HubSpot Page Fetcher',
|
||||
IFRAMELY: 'Iframely',
|
||||
KAKAOTALK_SCRAP: 'kakaotalk-scrap',
|
||||
KEYBASE_BOT: 'KeybaseBot',
|
||||
META_EXTERNALFETCHER: 'meta-externalfetcher',
|
||||
META_WHATSAPP: 'WhatsApp',
|
||||
MICROSOFT_BINGPREVIEW: 'BingPreview',
|
||||
@@ -669,9 +654,6 @@ const Extension = Object.freeze({
|
||||
PERPLEXITY_USER: 'Perplexity-User',
|
||||
PINTEREST_BOT: 'Pinterestbot',
|
||||
SEMRUSH_SITEAUDITBOT: 'SiteAuditBot',
|
||||
SLACK_BOT: 'Slackbot',
|
||||
SLACK_BOT_LINKEXPANDING: 'Slackbot-LinkExpanding',
|
||||
SLACK_IMGPROXY: 'Slack-ImgProxy',
|
||||
SNAP_URL_PREVIEW: 'Snap URL Preview',
|
||||
SKYPE_URIPREVIEW: 'SkypeUriPreview',
|
||||
TELEGRAM_BOT: 'TelegramBot',
|
||||
@@ -681,7 +663,6 @@ const Extension = Object.freeze({
|
||||
VERCEL_BOT: 'Vercelbot',
|
||||
VERCEL_FLAGS: 'vercelflags',
|
||||
VERCEL_TRACING: 'verceltracing',
|
||||
X_TWITTERBOT: 'Twitterbot',
|
||||
YANDEX_CALENDAR: 'YandexCalendar',
|
||||
YANDEX_DIRECT: 'YandexDirect',
|
||||
YANDEX_DIRECTDYN: 'YandexDirectDyn',
|
||||
@@ -714,13 +695,9 @@ const Extension = Object.freeze({
|
||||
AIOHTTP: 'aiohttp',
|
||||
APACHE_HTTPCLIENT: 'Apache-HttpClient',
|
||||
AXIOS: 'axios',
|
||||
BUN: 'Bun',
|
||||
DART: 'Dart',
|
||||
DENO: 'Deno',
|
||||
GO_HTTP_CLIENT: 'go-http-client',
|
||||
GOT: 'got',
|
||||
GUZZLEHTTP: 'GuzzleHttp',
|
||||
HACKNEY: 'hackney',
|
||||
JAVA: 'Java',
|
||||
JAVA_HTTPCLIENT: 'Java-http-client',
|
||||
JSDOM: 'jsdom',
|
||||
@@ -728,19 +705,16 @@ const Extension = Object.freeze({
|
||||
LUA_RESTY_HTTP: 'lua-resty-http',
|
||||
NEEDLE: 'Needle',
|
||||
NUTCH: 'Nutch',
|
||||
NODE_FETCH: 'node-fetch',
|
||||
NODE_JS: 'Node.js',
|
||||
NODE_SUPERAGENT: 'node-superagent',
|
||||
OKHTTP: 'OkHttp',
|
||||
NODE_FETCH: 'node-fetch',
|
||||
NODE_SUPERAGENT: 'node-superagent',
|
||||
PHP_SOAP: 'PHP-SOAP',
|
||||
POSTMAN_RUNTIME: 'PostmanRuntime',
|
||||
PYTHON_HTTPX: 'python-httpx',
|
||||
PYTHON_URLLIB: 'python-urllib',
|
||||
PYTHON_URLLIB3: 'python-urllib3',
|
||||
PYTHON_REQUESTS: 'python-requests',
|
||||
REST_CLIENT: 'rest-client',
|
||||
SCRAPY: 'Scrapy',
|
||||
UNDICI: 'undici'
|
||||
SCRAPY: 'Scrapy'
|
||||
}
|
||||
},
|
||||
DeviceVendor: {
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
///////////////////////////////////////////////
|
||||
/* Extensions for UAParser.js v2.0.7
|
||||
/* Extensions for UAParser.js v2.0.5
|
||||
https://github.com/faisalman/ua-parser-js
|
||||
Author: Faisal Salman <f@faisalman.com>
|
||||
AGPLv3 License */
|
||||
UAParser.js PRO Personal License */
|
||||
//////////////////////////////////////////////
|
||||
|
||||
/*jshint esversion: 6 */
|
||||
@@ -63,10 +63,8 @@ const Crawlers = Object.freeze({
|
||||
// PerplexityBot - https://perplexity.ai/perplexitybot
|
||||
// SBIntuitionsBot - https://www.sbintuitions.co.jp/bot/
|
||||
// SeznamBot - http://napoveda.seznam.cz/seznambot-intro
|
||||
// SurdotlyBot - http://sur.ly/bot.html
|
||||
// Swiftbot - https://swiftype.com/swiftbot
|
||||
// YepBot - https://yep.com/yepbot/
|
||||
/((?:adidx|ahrefs|amazon|bing|brave|cc|contx|coveo|criteo|dot|duckduck(?:go-favicons-)?|exa|facebook|gpt|iask|kagi|kangaroo |linkedin|mj12|mojeek|oai-search|onespot-scraper|perplexity|sbintuitions|semrush|seznam|surdotly|swift|yep)bot)\/([\w\.-]+)/i,
|
||||
/((?:adidx|ahrefs|amazon|bing|brave|cc|contx|coveo|criteo|dot|duckduck(?:go-favicons-)?|exa|facebook|gpt|iask|kagi|kangaroo |linkedin|mj12|mojeek|oai-search|onespot-scraper|perplexity|sbintuitions|semrush|seznam|yep)bot)\/([\w\.-]+)/i,
|
||||
|
||||
// Algolia Crawler
|
||||
/(algolia crawler(?: renderscript)?)\/?([\w\.]*)/i,
|
||||
@@ -100,7 +98,7 @@ const Crawlers = Object.freeze({
|
||||
/(oncrawl) mobile\/([\w\.]+)/i,
|
||||
|
||||
// Qwantbot - https://help.qwant.com/bot
|
||||
/(qwantbot(?:-news)?)[-\w]*\/?([\w\.]*)/i,
|
||||
/(qwantbot)[-\w]*\/?([\w\.]*)/i,
|
||||
|
||||
// SemrushBot - http://www.semrush.com/bot.html
|
||||
/((?:semrush|splitsignal)bot[-abcfimostw]*)\/?([\w\.-]*)/i,
|
||||
@@ -258,7 +256,7 @@ const Emails = Object.freeze({
|
||||
const Fetchers = Object.freeze({
|
||||
browser : [
|
||||
[
|
||||
// Asana / Bitlybot / Better Uptime / BingPreview / Blueno / Cohere-AI / HubSpot Page Fetcher / kakaotalk-scrap / Mastodon / MicrosoftPreview / Pinterestbot / Redditbot / Rogerbot / SiteAuditBot / Telegrambot / Twitterbot / UptimeRobot / WhatsApp
|
||||
// Asana / Bitlybot / Better Uptime / BingPreview / Blueno / Cohere-AI / HubSpot Page Fetcher / kakaotalk-scrap / Mastodon / MicrosoftPreview / Pinterestbot / Redditbot / Rogerbot / SiteAuditBot / Telegrambot / Twitterbot / UptimeRobot
|
||||
// AhrefsSiteAudit - https://ahrefs.com/robot/site-audit
|
||||
// Buffer Link Preview Bot - https://scraper.buffer.com/about/bots/link-preview-bot
|
||||
// ChatGPT-User - https://platform.openai.com/docs/plugins/bot
|
||||
@@ -268,25 +266,25 @@ const Fetchers = Object.freeze({
|
||||
// Perplexity-User - https://docs.perplexity.ai/guides/bots
|
||||
// MistralAI-User - https://docs.mistral.ai/robots/
|
||||
// Yandex Bots - https://yandex.com/bots
|
||||
/(asana|ahrefssiteaudit|(?:bing|microsoft)preview|blueno|(?:chatgpt|claude|mistralai|perplexity)-user|cohere-ai|hubspot page fetcher|mastodon|(?:bitly|bufferlinkpreview|discord|duckassist|linkedin|pinterest|reddit|roger|siteaudit|twitter|uptimero|zoom)bot|google-site-verification|iframely|kakaotalk-scrap|meta-externalfetcher|y!?j-dlc|yandex(?:calendar|direct(?:dyn)?|fordomain|pagechecker|searchshop)|yadirectfetcher|whatsapp)\/([\w\.]+)/i,
|
||||
/(asana|ahrefssiteaudit|(?:bing|microsoft)preview|blueno|(?:chatgpt|claude|mistralai|perplexity)-user|cohere-ai|hubspot page fetcher|mastodon|(?:bitly|bufferlinkpreview|discord|duckassist|linkedin|pinterest|reddit|roger|siteaudit|twitter|uptimero|zoom)bot|google-site-verification|iframely|kakaotalk-scrap|meta-externalfetcher|y!?j-dlc|yandex(?:calendar|direct(?:dyn)?|fordomain|pagechecker|searchshop)|yadirectfetcher)\/([\w\.]+)/i,
|
||||
|
||||
// Bluesky
|
||||
/(bluesky) cardyb\/([\w\.]+)/i,
|
||||
|
||||
// Nova Act - https://github.com/aws/nova-act
|
||||
/agent-(novaact)\/([\w\.]+)/i,
|
||||
|
||||
// Skype
|
||||
/(skypeuripreview) preview\/([\w\.]+)/i,
|
||||
|
||||
// Slackbot - https://api.slack.com/robots
|
||||
/(slack(?:bot)?(?:-imgproxy|-linkexpanding)?) ([\w\.]+)/i
|
||||
/(slack(?:bot)?(?:-imgproxy|-linkexpanding)?) ([\w\.]+)/i,
|
||||
|
||||
// WhatsApp
|
||||
/(whatsapp)\/([\w\.]+)/i
|
||||
],
|
||||
[NAME, VERSION, [TYPE, FETCHER]],
|
||||
|
||||
[
|
||||
// Google Bots / Chrome-Lighthouse / Gemini-Deep-Research / KeybaseBot / Snapchat / Vercelbot / Yandex Bots
|
||||
/((?:better uptime |keybase|telegram|vercel)bot|chrome-lighthouse|feedfetcher-google|gemini-deep-research|google(?:imageproxy|-read-aloud|-pagerenderer|producer)|snap url preview|vercel(flags|tracing|-(favicon|screenshot)-bot)|yandex(?:sitelinks|userproxy))/i
|
||||
// Google Bots / Chrome-Lighthouse / Gemini-Deep-Research / Snapchat / Vercelbot / Yandex Bots
|
||||
/((?:better uptime |telegram|vercel)bot|chrome-lighthouse|feedfetcher-google|gemini-deep-research|google(?:imageproxy|-read-aloud|-pagerenderer|producer)|snap url preview|vercel(flags|tracing|-(favicon|screenshot)-bot)|yandex(?:sitelinks|userproxy))/i
|
||||
],
|
||||
[NAME, [TYPE, FETCHER]],
|
||||
],
|
||||
@@ -389,15 +387,13 @@ const MediaPlayers = Object.freeze({
|
||||
|
||||
const Libraries = Object.freeze({
|
||||
browser : [
|
||||
// Apache-HttpClient/Axios/go-http-client/got/GuzzleHttp/Java[-HttpClient]/jsdom/libwww-perl/lua-resty-http/Needle/node-fetch/OkHttp/PHP-SOAP/PostmanRuntime/python-urllib/python-requests/Scrapy/superagent
|
||||
[
|
||||
// Apache-HttpClient/Axios/Bun/Dart/go-http-client/got/GuzzleHttp/hackney/Java[-HttpClient]/jsdom/libwww-perl/lua-resty-http/Needle/Node.js/node-fetch/OkHttp/PHP-SOAP/PostmanRuntime/python-urllib/python-requests/rest-client/Scrapy/superagent
|
||||
/^(apache-httpclient|axios|bun|dart|deno|(?:go|java)-http-client|got|guzzlehttp|hackney|java|libwww-perl|lua-resty-http|needle|node(?:\.js|-fetch|-superagent)|okhttp|php-soap|postmanruntime|python-(?:httpx|urllib[23]?|requests)|rest-client|scrapy)\/([\w\.]+)/i,
|
||||
/^(apache-httpclient|axios|(?:go|java)-http-client|got|guzzlehttp|java|libwww-perl|lua-resty-http|needle|node-(?:fetch|superagent)|okhttp|php-soap|postmanruntime|python-(?:httpx|urllib[23]?|requests)|scrapy)\/([\w\.]+)/i,
|
||||
/(adobeair|aiohttp|jsdom)\/([\w\.]+)/i,
|
||||
/(nutch)-([\w\.-]+)(\(|$)/i,
|
||||
/\((java)\/([\w\.]+)/i
|
||||
], [NAME, VERSION, [TYPE, LIBRARY]], [
|
||||
/(node-fetch|undici)/i
|
||||
], [NAME, [TYPE, LIBRARY]]
|
||||
], [NAME, VERSION, [TYPE, LIBRARY]]
|
||||
]
|
||||
});
|
||||
|
||||
|
||||
@@ -3,10 +3,10 @@
|
||||
// Source: /src/extensions/ua-parser-extensions.js
|
||||
|
||||
///////////////////////////////////////////////
|
||||
/* Extensions for UAParser.js v2.0.7
|
||||
/* Extensions for UAParser.js v2.0.5
|
||||
https://github.com/faisalman/ua-parser-js
|
||||
Author: Faisal Salman <f@faisalman.com>
|
||||
AGPLv3 License */
|
||||
UAParser.js PRO Personal License */
|
||||
//////////////////////////////////////////////
|
||||
|
||||
/*jshint esversion: 6 */
|
||||
@@ -67,10 +67,8 @@ const Crawlers = Object.freeze({
|
||||
// PerplexityBot - https://perplexity.ai/perplexitybot
|
||||
// SBIntuitionsBot - https://www.sbintuitions.co.jp/bot/
|
||||
// SeznamBot - http://napoveda.seznam.cz/seznambot-intro
|
||||
// SurdotlyBot - http://sur.ly/bot.html
|
||||
// Swiftbot - https://swiftype.com/swiftbot
|
||||
// YepBot - https://yep.com/yepbot/
|
||||
/((?:adidx|ahrefs|amazon|bing|brave|cc|contx|coveo|criteo|dot|duckduck(?:go-favicons-)?|exa|facebook|gpt|iask|kagi|kangaroo |linkedin|mj12|mojeek|oai-search|onespot-scraper|perplexity|sbintuitions|semrush|seznam|surdotly|swift|yep)bot)\/([\w\.-]+)/i,
|
||||
/((?:adidx|ahrefs|amazon|bing|brave|cc|contx|coveo|criteo|dot|duckduck(?:go-favicons-)?|exa|facebook|gpt|iask|kagi|kangaroo |linkedin|mj12|mojeek|oai-search|onespot-scraper|perplexity|sbintuitions|semrush|seznam|yep)bot)\/([\w\.-]+)/i,
|
||||
|
||||
// Algolia Crawler
|
||||
/(algolia crawler(?: renderscript)?)\/?([\w\.]*)/i,
|
||||
@@ -104,7 +102,7 @@ const Crawlers = Object.freeze({
|
||||
/(oncrawl) mobile\/([\w\.]+)/i,
|
||||
|
||||
// Qwantbot - https://help.qwant.com/bot
|
||||
/(qwantbot(?:-news)?)[-\w]*\/?([\w\.]*)/i,
|
||||
/(qwantbot)[-\w]*\/?([\w\.]*)/i,
|
||||
|
||||
// SemrushBot - http://www.semrush.com/bot.html
|
||||
/((?:semrush|splitsignal)bot[-abcfimostw]*)\/?([\w\.-]*)/i,
|
||||
@@ -262,7 +260,7 @@ const Emails = Object.freeze({
|
||||
const Fetchers = Object.freeze({
|
||||
browser : [
|
||||
[
|
||||
// Asana / Bitlybot / Better Uptime / BingPreview / Blueno / Cohere-AI / HubSpot Page Fetcher / kakaotalk-scrap / Mastodon / MicrosoftPreview / Pinterestbot / Redditbot / Rogerbot / SiteAuditBot / Telegrambot / Twitterbot / UptimeRobot / WhatsApp
|
||||
// Asana / Bitlybot / Better Uptime / BingPreview / Blueno / Cohere-AI / HubSpot Page Fetcher / kakaotalk-scrap / Mastodon / MicrosoftPreview / Pinterestbot / Redditbot / Rogerbot / SiteAuditBot / Telegrambot / Twitterbot / UptimeRobot
|
||||
// AhrefsSiteAudit - https://ahrefs.com/robot/site-audit
|
||||
// Buffer Link Preview Bot - https://scraper.buffer.com/about/bots/link-preview-bot
|
||||
// ChatGPT-User - https://platform.openai.com/docs/plugins/bot
|
||||
@@ -272,25 +270,25 @@ const Fetchers = Object.freeze({
|
||||
// Perplexity-User - https://docs.perplexity.ai/guides/bots
|
||||
// MistralAI-User - https://docs.mistral.ai/robots/
|
||||
// Yandex Bots - https://yandex.com/bots
|
||||
/(asana|ahrefssiteaudit|(?:bing|microsoft)preview|blueno|(?:chatgpt|claude|mistralai|perplexity)-user|cohere-ai|hubspot page fetcher|mastodon|(?:bitly|bufferlinkpreview|discord|duckassist|linkedin|pinterest|reddit|roger|siteaudit|twitter|uptimero|zoom)bot|google-site-verification|iframely|kakaotalk-scrap|meta-externalfetcher|y!?j-dlc|yandex(?:calendar|direct(?:dyn)?|fordomain|pagechecker|searchshop)|yadirectfetcher|whatsapp)\/([\w\.]+)/i,
|
||||
/(asana|ahrefssiteaudit|(?:bing|microsoft)preview|blueno|(?:chatgpt|claude|mistralai|perplexity)-user|cohere-ai|hubspot page fetcher|mastodon|(?:bitly|bufferlinkpreview|discord|duckassist|linkedin|pinterest|reddit|roger|siteaudit|twitter|uptimero|zoom)bot|google-site-verification|iframely|kakaotalk-scrap|meta-externalfetcher|y!?j-dlc|yandex(?:calendar|direct(?:dyn)?|fordomain|pagechecker|searchshop)|yadirectfetcher)\/([\w\.]+)/i,
|
||||
|
||||
// Bluesky
|
||||
/(bluesky) cardyb\/([\w\.]+)/i,
|
||||
|
||||
// Nova Act - https://github.com/aws/nova-act
|
||||
/agent-(novaact)\/([\w\.]+)/i,
|
||||
|
||||
// Skype
|
||||
/(skypeuripreview) preview\/([\w\.]+)/i,
|
||||
|
||||
// Slackbot - https://api.slack.com/robots
|
||||
/(slack(?:bot)?(?:-imgproxy|-linkexpanding)?) ([\w\.]+)/i
|
||||
/(slack(?:bot)?(?:-imgproxy|-linkexpanding)?) ([\w\.]+)/i,
|
||||
|
||||
// WhatsApp
|
||||
/(whatsapp)\/([\w\.]+)/i
|
||||
],
|
||||
[NAME, VERSION, [TYPE, FETCHER]],
|
||||
|
||||
[
|
||||
// Google Bots / Chrome-Lighthouse / Gemini-Deep-Research / KeybaseBot / Snapchat / Vercelbot / Yandex Bots
|
||||
/((?:better uptime |keybase|telegram|vercel)bot|chrome-lighthouse|feedfetcher-google|gemini-deep-research|google(?:imageproxy|-read-aloud|-pagerenderer|producer)|snap url preview|vercel(flags|tracing|-(favicon|screenshot)-bot)|yandex(?:sitelinks|userproxy))/i
|
||||
// Google Bots / Chrome-Lighthouse / Gemini-Deep-Research / Snapchat / Vercelbot / Yandex Bots
|
||||
/((?:better uptime |telegram|vercel)bot|chrome-lighthouse|feedfetcher-google|gemini-deep-research|google(?:imageproxy|-read-aloud|-pagerenderer|producer)|snap url preview|vercel(flags|tracing|-(favicon|screenshot)-bot)|yandex(?:sitelinks|userproxy))/i
|
||||
],
|
||||
[NAME, [TYPE, FETCHER]],
|
||||
],
|
||||
@@ -393,15 +391,13 @@ const MediaPlayers = Object.freeze({
|
||||
|
||||
const Libraries = Object.freeze({
|
||||
browser : [
|
||||
// Apache-HttpClient/Axios/go-http-client/got/GuzzleHttp/Java[-HttpClient]/jsdom/libwww-perl/lua-resty-http/Needle/node-fetch/OkHttp/PHP-SOAP/PostmanRuntime/python-urllib/python-requests/Scrapy/superagent
|
||||
[
|
||||
// Apache-HttpClient/Axios/Bun/Dart/go-http-client/got/GuzzleHttp/hackney/Java[-HttpClient]/jsdom/libwww-perl/lua-resty-http/Needle/Node.js/node-fetch/OkHttp/PHP-SOAP/PostmanRuntime/python-urllib/python-requests/rest-client/Scrapy/superagent
|
||||
/^(apache-httpclient|axios|bun|dart|deno|(?:go|java)-http-client|got|guzzlehttp|hackney|java|libwww-perl|lua-resty-http|needle|node(?:\.js|-fetch|-superagent)|okhttp|php-soap|postmanruntime|python-(?:httpx|urllib[23]?|requests)|rest-client|scrapy)\/([\w\.]+)/i,
|
||||
/^(apache-httpclient|axios|(?:go|java)-http-client|got|guzzlehttp|java|libwww-perl|lua-resty-http|needle|node-(?:fetch|superagent)|okhttp|php-soap|postmanruntime|python-(?:httpx|urllib[23]?|requests)|scrapy)\/([\w\.]+)/i,
|
||||
/(adobeair|aiohttp|jsdom)\/([\w\.]+)/i,
|
||||
/(nutch)-([\w\.-]+)(\(|$)/i,
|
||||
/\((java)\/([\w\.]+)/i
|
||||
], [NAME, VERSION, [TYPE, LIBRARY]], [
|
||||
/(node-fetch|undici)/i
|
||||
], [NAME, [TYPE, LIBRARY]]
|
||||
], [NAME, VERSION, [TYPE, LIBRARY]]
|
||||
]
|
||||
});
|
||||
|
||||
|
||||
27
src/helpers/ua-parser-helpers.d.ts
vendored
27
src/helpers/ua-parser-helpers.d.ts
vendored
@@ -4,37 +4,12 @@
|
||||
|
||||
import type { IResult } from "../main/ua-parser";
|
||||
|
||||
export function isFrozenUA(ua: string): boolean;
|
||||
|
||||
/**
|
||||
* @deprecated Moved to `device-detection` submodule
|
||||
*/
|
||||
export function getDeviceVendor(model: string): string | undefined;
|
||||
/**
|
||||
* @deprecated Moved to `device-detection` submodule
|
||||
*/
|
||||
export function isAppleSilicon(resultOrUA: IResult | string): boolean;
|
||||
/**
|
||||
* @deprecated Moved to `bot-detection` submodule
|
||||
*/
|
||||
export function isAIBot(resultOrUA: IResult | string): boolean;
|
||||
/**
|
||||
* @deprecated Moved to `bot-detection` submodule
|
||||
*/
|
||||
export function isBot(resultOrUA: IResult | string): boolean;
|
||||
/**
|
||||
* @deprecated Moved to `browser-detection` submodule
|
||||
*/
|
||||
export function isChromeFamily(resultOrUA: IResult | string): boolean;
|
||||
/**
|
||||
* @deprecated Moved to `browser-detection` submodule
|
||||
*/
|
||||
export function isElectron(): boolean;
|
||||
/**
|
||||
* @deprecated Moved to `browser-detection` submodule
|
||||
*/
|
||||
export function isFromEU(): boolean;
|
||||
/**
|
||||
* @deprecated Moved to `browser-detection` submodule
|
||||
*/
|
||||
export function isFrozenUA(ua: string): boolean;
|
||||
export function isStandalonePWA(): boolean;
|
||||
@@ -1,59 +1,176 @@
|
||||
///////////////////////////////////////////////
|
||||
/* Helpers for UAParser.js v2.0.7
|
||||
/* Helpers for UAParser.js v2.0.5
|
||||
https://github.com/faisalman/ua-parser-js
|
||||
Author: Faisal Salman <f@faisalman.com>
|
||||
AGPLv3 License */
|
||||
UAParser.js PRO Personal License */
|
||||
//////////////////////////////////////////////
|
||||
|
||||
/*jshint esversion: 6 */
|
||||
|
||||
const { UAParser } = require('../main/ua-parser');
|
||||
const { EngineName } = require('../enums/ua-parser-enums');
|
||||
const { getDeviceVendor: _getDeviceVendor, isAppleSilicon: _isAppleSilicon } = require('../device-detection/device-detection');
|
||||
const { isBot: _isBot, isAICrawler } = require('../bot-detection/bot-detection');
|
||||
const { isChromeFamily: _isChromeFamily, isElectron: _isElectron, isStandalonePWA: _isStandalonePWA } = require('../browser-detection/browser-detection');
|
||||
const { isFromEU: _isFromEU } = require('../browser-detection/browser-detection');
|
||||
const { CPUArch, OSName, EngineName, Extension, BrowserType } = require('../enums/ua-parser-enums');
|
||||
const { Bots, Crawlers } = require('../extensions/ua-parser-extensions');
|
||||
const { isFromEU } = require('detect-europe-js');
|
||||
const { isFrozenUA } = require('ua-is-frozen');
|
||||
const { isStandalonePWA } = require('is-standalone-pwa');
|
||||
const { Crawler } = Extension.BrowserName;
|
||||
|
||||
/**
|
||||
* @deprecated Moved to `device-detection` submodule
|
||||
*/
|
||||
const getDeviceVendor = _getDeviceVendor;
|
||||
const toResult = (value, head, ext) => typeof value === 'string' ? UAParser(value, head, ext) : value;
|
||||
|
||||
/**
|
||||
* @deprecated Moved to `device-detection` submodule
|
||||
*/
|
||||
const isAppleSilicon = _isAppleSilicon;
|
||||
const getDeviceVendor = (model) => UAParser(`Mozilla/5.0 (Linux; Android 10; ${model}) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/100.0.0.0 Safari/537.36`).device.vendor;
|
||||
|
||||
/**
|
||||
* @deprecated Moved to `bot-detection` submodule
|
||||
*/
|
||||
const isAIBot = isAICrawler;
|
||||
const isAppleSilicon = (resultOrUA) => {
|
||||
const res = toResult(resultOrUA);
|
||||
if (res.os.is(OSName.MACOS)) {
|
||||
if (res.cpu.is(CPUArch.ARM)) {
|
||||
return true;
|
||||
}
|
||||
if (typeof resultOrUA !== 'string' && typeof window !== 'undefined') {
|
||||
try {
|
||||
const canvas = document.createElement('canvas');
|
||||
const webgl = canvas.getContext('webgl2') || canvas.getContext('webgl') || canvas.getContext('experimental-webgl');
|
||||
const debug = webgl.getExtension('WEBGL_debug_renderer_info');
|
||||
const renderer = webgl.getParameter(debug.UNMASKED_RENDERER_WEBGL);
|
||||
if (renderer.match(/apple m\d/i)) {
|
||||
return true;
|
||||
}
|
||||
} catch {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* @deprecated Moved to `bot-detection` submodule
|
||||
*/
|
||||
const isBot = _isBot;
|
||||
const isAIBot = (resultOrUA) => [
|
||||
|
||||
/**
|
||||
* @deprecated Moved to `browser-detection` submodule
|
||||
*/
|
||||
const isChromeFamily = _isChromeFamily;
|
||||
// AI2
|
||||
Crawler.AI2_BOT,
|
||||
|
||||
/**
|
||||
* @deprecated Moved to `browser-detection` submodule
|
||||
*/
|
||||
const isElectron = () => _isElectron;
|
||||
// Amazon
|
||||
Crawler.AMAZON_BOT,
|
||||
|
||||
/**
|
||||
* @deprecated Moved to `browser-detection` submodule
|
||||
*/
|
||||
const isFromEU = _isFromEU;
|
||||
// Anthropic
|
||||
Crawler.ANTHROPIC_AI,
|
||||
Crawler.ANTHROPIC_CLAUDE_BOT,
|
||||
Crawler.ANTHROPIC_CLAUDE_SEARCHBOT,
|
||||
Crawler.ANTHROPIC_CLAUDE_WEB,
|
||||
|
||||
/**
|
||||
* @deprecated Moved to `browser-detection` submodule
|
||||
*/
|
||||
const isStandalonePWA = _isStandalonePWA;
|
||||
// Apple
|
||||
Crawler.APPLE_BOT,
|
||||
Crawler.APPLE_BOT_EXTENDED,
|
||||
|
||||
// Brave
|
||||
Crawler.BRAVE_BOT,
|
||||
|
||||
// ByteDance
|
||||
Crawler.BYTEDANCE_BYTESPIDER,
|
||||
Crawler.BYTEDANCE_TIKTOKSPIDER,
|
||||
|
||||
// Cohere
|
||||
Crawler.COHERE_TRAINING_DATA_CRAWLER,
|
||||
|
||||
// Common Crawl
|
||||
Crawler.COMMON_CRAWL_CCBOT,
|
||||
|
||||
// Coveo
|
||||
Crawler.COVEO_BOT,
|
||||
|
||||
// DataForSeo
|
||||
Crawler.DATAFORSEO_BOT,
|
||||
|
||||
// DeepSeek
|
||||
Crawler.DEEPSEEK_BOT,
|
||||
|
||||
// Diffbot
|
||||
Crawler.DIFFBOT,
|
||||
|
||||
// Google
|
||||
Crawler.GOOGLE_EXTENDED,
|
||||
Crawler.GOOGLE_OTHER,
|
||||
Crawler.GOOGLE_OTHER_IMAGE,
|
||||
Crawler.GOOGLE_OTHER_VIDEO,
|
||||
Crawler.GOOGLE_CLOUDVERTEXBOT,
|
||||
|
||||
// Hive AI
|
||||
Crawler.HIVE_IMAGESIFTBOT,
|
||||
|
||||
// Huawei
|
||||
Crawler.HUAWEI_PETALBOT,
|
||||
Crawler.HUAWEI_PANGUBOT,
|
||||
|
||||
// Hugging Face
|
||||
Crawler.HUGGINGFACE_BOT,
|
||||
|
||||
// Kangaroo
|
||||
Crawler.KANGAROO_BOT,
|
||||
|
||||
// Mendable.ai
|
||||
Crawler.FIRECRAWL_AGENT,
|
||||
|
||||
// Meta
|
||||
Crawler.META_FACEBOOKBOT,
|
||||
Crawler.META_EXTERNALAGENT,
|
||||
|
||||
// OpenAI
|
||||
Crawler.OPENAI_GPTBOT,
|
||||
Crawler.OPENAI_SEARCH_BOT,
|
||||
|
||||
// Perplexity
|
||||
Crawler.PERPLEXITY_BOT,
|
||||
|
||||
// Replicate
|
||||
Crawler.REPLICATE_BOT,
|
||||
|
||||
// Runpod
|
||||
Crawler.RUNPOD_BOT,
|
||||
|
||||
// SB Intuitions
|
||||
Crawler.SB_INTUITIONS_BOT,
|
||||
|
||||
// Semrush
|
||||
Crawler.SEMRUSH_BOT_CONTENTSHAKE,
|
||||
|
||||
// Timpi
|
||||
Crawler.TIMPI_BOT,
|
||||
|
||||
// Together AI
|
||||
Crawler.TOGETHER_BOT,
|
||||
|
||||
// Velen.io
|
||||
Crawler.HUNTER_VELENPUBLICWEBCRAWLER,
|
||||
|
||||
// Vercel
|
||||
Crawler.VERCEL_V0BOT,
|
||||
|
||||
// Webz.io
|
||||
Crawler.WEBZIO_OMGILI,
|
||||
Crawler.WEBZIO_OMGILI_BOT,
|
||||
Crawler.WEBZIO_EXTENDED,
|
||||
|
||||
// X
|
||||
Crawler.XAI_BOT,
|
||||
|
||||
// You.com
|
||||
Crawler.YOU_BOT,
|
||||
|
||||
// Zhipu AI
|
||||
Crawler.ZHIPU_CHATGLM_SPIDER
|
||||
]
|
||||
.map((s) => s.toLowerCase())
|
||||
.includes(String(toResult(resultOrUA, Crawlers).browser.name).toLowerCase());
|
||||
|
||||
const isBot = (resultOrUA) => [
|
||||
BrowserType.CLI,
|
||||
BrowserType.CRAWLER,
|
||||
BrowserType.FETCHER,
|
||||
BrowserType.LIBRARY
|
||||
].includes(toResult(resultOrUA, Bots).browser.type);
|
||||
|
||||
const isChromeFamily = (resultOrUA) => toResult(resultOrUA).engine.is(EngineName.BLINK);
|
||||
|
||||
const isElectron = () => !!(process?.versions?.hasOwnProperty('electron') || // node.js
|
||||
/ electron\//i.test(navigator?.userAgent)); // browser
|
||||
|
||||
module.exports = {
|
||||
getDeviceVendor,
|
||||
|
||||
@@ -3,61 +3,178 @@
|
||||
// Source: /src/helpers/ua-parser-helpers.js
|
||||
|
||||
///////////////////////////////////////////////
|
||||
/* Helpers for UAParser.js v2.0.7
|
||||
/* Helpers for UAParser.js v2.0.5
|
||||
https://github.com/faisalman/ua-parser-js
|
||||
Author: Faisal Salman <f@faisalman.com>
|
||||
AGPLv3 License */
|
||||
UAParser.js PRO Personal License */
|
||||
//////////////////////////////////////////////
|
||||
|
||||
/*jshint esversion: 6 */
|
||||
|
||||
import { UAParser } from '../main/ua-parser.mjs';
|
||||
import { EngineName } from '../enums/ua-parser-enums.mjs';
|
||||
import { getDeviceVendor: _getDeviceVendor, isAppleSilicon: _isAppleSilicon } from '../device-detection/device-detection.mjs';
|
||||
import { isBot: _isBot, isAICrawler } from '../bot-detection/bot-detection.mjs';
|
||||
import { isChromeFamily: _isChromeFamily, isElectron: _isElectron, isStandalonePWA: _isStandalonePWA } from '../browser-detection/browser-detection.mjs';
|
||||
import { isFromEU: _isFromEU } from '../browser-detection/browser-detection.mjs';
|
||||
import { CPUArch, OSName, EngineName, Extension, BrowserType } from '../enums/ua-parser-enums.mjs';
|
||||
import { Bots, Crawlers } from '../extensions/ua-parser-extensions.mjs';
|
||||
import { isFromEU } from 'detect-europe-js';
|
||||
import { isFrozenUA } from 'ua-is-frozen';
|
||||
import { isStandalonePWA } from 'is-standalone-pwa';
|
||||
const { Crawler } = Extension.BrowserName;
|
||||
|
||||
/**
|
||||
* @deprecated Moved to `device-detection` submodule
|
||||
*/
|
||||
const getDeviceVendor = _getDeviceVendor;
|
||||
const toResult = (value, head, ext) => typeof value === 'string' ? UAParser(value, head, ext) : value;
|
||||
|
||||
/**
|
||||
* @deprecated Moved to `device-detection` submodule
|
||||
*/
|
||||
const isAppleSilicon = _isAppleSilicon;
|
||||
const getDeviceVendor = (model) => UAParser(`Mozilla/5.0 (Linux; Android 10; ${model}) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/100.0.0.0 Safari/537.36`).device.vendor;
|
||||
|
||||
/**
|
||||
* @deprecated Moved to `bot-detection` submodule
|
||||
*/
|
||||
const isAIBot = isAICrawler;
|
||||
const isAppleSilicon = (resultOrUA) => {
|
||||
const res = toResult(resultOrUA);
|
||||
if (res.os.is(OSName.MACOS)) {
|
||||
if (res.cpu.is(CPUArch.ARM)) {
|
||||
return true;
|
||||
}
|
||||
if (typeof resultOrUA !== 'string' && typeof window !== 'undefined') {
|
||||
try {
|
||||
const canvas = document.createElement('canvas');
|
||||
const webgl = canvas.getContext('webgl2') || canvas.getContext('webgl') || canvas.getContext('experimental-webgl');
|
||||
const debug = webgl.getExtension('WEBGL_debug_renderer_info');
|
||||
const renderer = webgl.getParameter(debug.UNMASKED_RENDERER_WEBGL);
|
||||
if (renderer.match(/apple m\d/i)) {
|
||||
return true;
|
||||
}
|
||||
} catch {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* @deprecated Moved to `bot-detection` submodule
|
||||
*/
|
||||
const isBot = _isBot;
|
||||
const isAIBot = (resultOrUA) => [
|
||||
|
||||
/**
|
||||
* @deprecated Moved to `browser-detection` submodule
|
||||
*/
|
||||
const isChromeFamily = _isChromeFamily;
|
||||
// AI2
|
||||
Crawler.AI2_BOT,
|
||||
|
||||
/**
|
||||
* @deprecated Moved to `browser-detection` submodule
|
||||
*/
|
||||
const isElectron = () => _isElectron;
|
||||
// Amazon
|
||||
Crawler.AMAZON_BOT,
|
||||
|
||||
/**
|
||||
* @deprecated Moved to `browser-detection` submodule
|
||||
*/
|
||||
const isFromEU = _isFromEU;
|
||||
// Anthropic
|
||||
Crawler.ANTHROPIC_AI,
|
||||
Crawler.ANTHROPIC_CLAUDE_BOT,
|
||||
Crawler.ANTHROPIC_CLAUDE_SEARCHBOT,
|
||||
Crawler.ANTHROPIC_CLAUDE_WEB,
|
||||
|
||||
/**
|
||||
* @deprecated Moved to `browser-detection` submodule
|
||||
*/
|
||||
const isStandalonePWA = _isStandalonePWA;
|
||||
// Apple
|
||||
Crawler.APPLE_BOT,
|
||||
Crawler.APPLE_BOT_EXTENDED,
|
||||
|
||||
// Brave
|
||||
Crawler.BRAVE_BOT,
|
||||
|
||||
// ByteDance
|
||||
Crawler.BYTEDANCE_BYTESPIDER,
|
||||
Crawler.BYTEDANCE_TIKTOKSPIDER,
|
||||
|
||||
// Cohere
|
||||
Crawler.COHERE_TRAINING_DATA_CRAWLER,
|
||||
|
||||
// Common Crawl
|
||||
Crawler.COMMON_CRAWL_CCBOT,
|
||||
|
||||
// Coveo
|
||||
Crawler.COVEO_BOT,
|
||||
|
||||
// DataForSeo
|
||||
Crawler.DATAFORSEO_BOT,
|
||||
|
||||
// DeepSeek
|
||||
Crawler.DEEPSEEK_BOT,
|
||||
|
||||
// Diffbot
|
||||
Crawler.DIFFBOT,
|
||||
|
||||
// Google
|
||||
Crawler.GOOGLE_EXTENDED,
|
||||
Crawler.GOOGLE_OTHER,
|
||||
Crawler.GOOGLE_OTHER_IMAGE,
|
||||
Crawler.GOOGLE_OTHER_VIDEO,
|
||||
Crawler.GOOGLE_CLOUDVERTEXBOT,
|
||||
|
||||
// Hive AI
|
||||
Crawler.HIVE_IMAGESIFTBOT,
|
||||
|
||||
// Huawei
|
||||
Crawler.HUAWEI_PETALBOT,
|
||||
Crawler.HUAWEI_PANGUBOT,
|
||||
|
||||
// Hugging Face
|
||||
Crawler.HUGGINGFACE_BOT,
|
||||
|
||||
// Kangaroo
|
||||
Crawler.KANGAROO_BOT,
|
||||
|
||||
// Mendable.ai
|
||||
Crawler.FIRECRAWL_AGENT,
|
||||
|
||||
// Meta
|
||||
Crawler.META_FACEBOOKBOT,
|
||||
Crawler.META_EXTERNALAGENT,
|
||||
|
||||
// OpenAI
|
||||
Crawler.OPENAI_GPTBOT,
|
||||
Crawler.OPENAI_SEARCH_BOT,
|
||||
|
||||
// Perplexity
|
||||
Crawler.PERPLEXITY_BOT,
|
||||
|
||||
// Replicate
|
||||
Crawler.REPLICATE_BOT,
|
||||
|
||||
// Runpod
|
||||
Crawler.RUNPOD_BOT,
|
||||
|
||||
// SB Intuitions
|
||||
Crawler.SB_INTUITIONS_BOT,
|
||||
|
||||
// Semrush
|
||||
Crawler.SEMRUSH_BOT_CONTENTSHAKE,
|
||||
|
||||
// Timpi
|
||||
Crawler.TIMPI_BOT,
|
||||
|
||||
// Together AI
|
||||
Crawler.TOGETHER_BOT,
|
||||
|
||||
// Velen.io
|
||||
Crawler.HUNTER_VELENPUBLICWEBCRAWLER,
|
||||
|
||||
// Vercel
|
||||
Crawler.VERCEL_V0BOT,
|
||||
|
||||
// Webz.io
|
||||
Crawler.WEBZIO_OMGILI,
|
||||
Crawler.WEBZIO_OMGILI_BOT,
|
||||
Crawler.WEBZIO_EXTENDED,
|
||||
|
||||
// X
|
||||
Crawler.XAI_BOT,
|
||||
|
||||
// You.com
|
||||
Crawler.YOU_BOT,
|
||||
|
||||
// Zhipu AI
|
||||
Crawler.ZHIPU_CHATGLM_SPIDER
|
||||
]
|
||||
.map((s) => s.toLowerCase())
|
||||
.includes(String(toResult(resultOrUA, Crawlers).browser.name).toLowerCase());
|
||||
|
||||
const isBot = (resultOrUA) => [
|
||||
BrowserType.CLI,
|
||||
BrowserType.CRAWLER,
|
||||
BrowserType.FETCHER,
|
||||
BrowserType.LIBRARY
|
||||
].includes(toResult(resultOrUA, Bots).browser.type);
|
||||
|
||||
const isChromeFamily = (resultOrUA) => toResult(resultOrUA).engine.is(EngineName.BLINK);
|
||||
|
||||
const isElectron = () => !!(process?.versions?.hasOwnProperty('electron') || // node.js
|
||||
/ electron\//i.test(navigator?.userAgent)); // browser
|
||||
|
||||
export {
|
||||
getDeviceVendor,
|
||||
|
||||
3
src/main/ua-parser.d.ts
vendored
3
src/main/ua-parser.d.ts
vendored
@@ -1,7 +1,8 @@
|
||||
// Type definitions for UAParser.js v2.0.7
|
||||
// Type definitions for UAParser.js v2.0.5
|
||||
// Project: https://github.com/faisalman/ua-parser-js
|
||||
// Definitions by: Faisal Salman <https://github.com/faisalman>
|
||||
|
||||
import type { Headers } from "undici";
|
||||
import { BrowserType, CPUArch, DeviceType, EngineName } from "../enums/ua-parser-enums";
|
||||
|
||||
declare namespace UAParser {
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
/////////////////////////////////////////////////////////////////////////////////
|
||||
/* UAParser.js v2.0.7
|
||||
/* UAParser.js v2.0.5
|
||||
Copyright © 2012-2025 Faisal Salman <f@faisalman.com>
|
||||
AGPLv3 License *//*
|
||||
UAParser.js PRO Personal License *//*
|
||||
Detect Browser, Engine, OS, CPU, and Device type/model from User-Agent data.
|
||||
Supports browser & node.js environment.
|
||||
Demo : https://uaparser.dev
|
||||
@@ -19,25 +19,25 @@
|
||||
// Constants
|
||||
/////////////
|
||||
|
||||
var LIBVERSION = '2.0.7',
|
||||
var LIBVERSION = '2.0.5',
|
||||
UA_MAX_LENGTH = 500,
|
||||
USER_AGENT = 'user-agent',
|
||||
EMPTY = '',
|
||||
UNKNOWN = '?',
|
||||
TYPEOF = {
|
||||
FUNCTION : 'function',
|
||||
OBJECT : 'object',
|
||||
STRING : 'string',
|
||||
UNDEFINED : 'undefined'
|
||||
},
|
||||
|
||||
// typeof
|
||||
FUNC_TYPE = 'function',
|
||||
UNDEF_TYPE = 'undefined',
|
||||
OBJ_TYPE = 'object',
|
||||
STR_TYPE = 'string',
|
||||
|
||||
// properties
|
||||
BROWSER = 'browser',
|
||||
CPU = 'cpu',
|
||||
DEVICE = 'device',
|
||||
ENGINE = 'engine',
|
||||
OS = 'os',
|
||||
RESULT = 'result',
|
||||
UA_BROWSER = 'browser',
|
||||
UA_CPU = 'cpu',
|
||||
UA_DEVICE = 'device',
|
||||
UA_ENGINE = 'engine',
|
||||
UA_OS = 'os',
|
||||
UA_RESULT = 'result',
|
||||
|
||||
NAME = 'name',
|
||||
TYPE = 'type',
|
||||
@@ -66,15 +66,15 @@
|
||||
PLATFORM = 'platform',
|
||||
PLATFORMVER = 'platformVersion',
|
||||
BITNESS = 'bitness',
|
||||
CH = 'sec-ch-ua',
|
||||
CH_FULL_VER_LIST= CH + '-full-version-list',
|
||||
CH_ARCH = CH + '-arch',
|
||||
CH_BITNESS = CH + '-' + BITNESS,
|
||||
CH_FORM_FACTORS = CH + '-form-factors',
|
||||
CH_MOBILE = CH + '-' + MOBILE,
|
||||
CH_MODEL = CH + '-' + MODEL,
|
||||
CH_PLATFORM = CH + '-' + PLATFORM,
|
||||
CH_PLATFORM_VER = CH_PLATFORM + '-version',
|
||||
CH_HEADER = 'sec-ch-ua',
|
||||
CH_HEADER_FULL_VER_LIST = CH_HEADER + '-full-version-list',
|
||||
CH_HEADER_ARCH = CH_HEADER + '-arch',
|
||||
CH_HEADER_BITNESS = CH_HEADER + '-' + BITNESS,
|
||||
CH_HEADER_FORM_FACTORS = CH_HEADER + '-form-factors',
|
||||
CH_HEADER_MOBILE = CH_HEADER + '-' + MOBILE,
|
||||
CH_HEADER_MODEL = CH_HEADER + '-' + MODEL,
|
||||
CH_HEADER_PLATFORM = CH_HEADER + '-' + PLATFORM,
|
||||
CH_HEADER_PLATFORM_VER = CH_HEADER_PLATFORM + '-version',
|
||||
CH_ALL_VALUES = [BRANDS, FULLVERLIST, MOBILE, MODEL, PLATFORM, PLATFORMVER, ARCHITECTURE, FORMFACTORS, BITNESS],
|
||||
|
||||
// device vendors
|
||||
@@ -114,7 +114,7 @@
|
||||
// os
|
||||
WINDOWS = 'Windows';
|
||||
|
||||
var isWindow = typeof window !== TYPEOF.UNDEFINED,
|
||||
var isWindow = typeof window !== UNDEF_TYPE,
|
||||
NAVIGATOR = (isWindow && window.navigator) ?
|
||||
window.navigator :
|
||||
undefined,
|
||||
@@ -150,7 +150,7 @@
|
||||
return enums;
|
||||
},
|
||||
has = function (str1, str2) {
|
||||
if (typeof str1 === TYPEOF.OBJECT && str1.length > 0) {
|
||||
if (typeof str1 === OBJ_TYPE && str1.length > 0) {
|
||||
for (var i in str1) {
|
||||
if (lowerize(str2) == lowerize(str1[i])) return true;
|
||||
}
|
||||
@@ -164,7 +164,7 @@
|
||||
}
|
||||
},
|
||||
isString = function (val) {
|
||||
return typeof val === TYPEOF.STRING;
|
||||
return typeof val === STR_TYPE;
|
||||
},
|
||||
itemListToArray = function (header) {
|
||||
if (!header) return undefined;
|
||||
@@ -191,7 +191,7 @@
|
||||
if (!arr.hasOwnProperty(i)) continue;
|
||||
|
||||
var propName = arr[i];
|
||||
if (typeof propName == TYPEOF.OBJECT && propName.length == 2) {
|
||||
if (typeof propName == OBJ_TYPE && propName.length == 2) {
|
||||
this[propName[0]] = propName[1];
|
||||
} else {
|
||||
this[propName] = undefined;
|
||||
@@ -206,8 +206,10 @@
|
||||
return strip(/\\?\"/g, str);
|
||||
},
|
||||
trim = function (str, len) {
|
||||
str = strip(/^\s\s*/, String(str));
|
||||
return typeof len === TYPEOF.UNDEFINED ? str : str.substring(0, len);
|
||||
if (isString(str)) {
|
||||
str = strip(/^\s\s*/, str);
|
||||
return typeof len === UNDEF_TYPE ? str : str.substring(0, UA_MAX_LENGTH);
|
||||
}
|
||||
};
|
||||
|
||||
///////////////
|
||||
@@ -238,9 +240,9 @@
|
||||
match = matches[++k];
|
||||
q = props[p];
|
||||
// check if given property is actually array
|
||||
if (typeof q === TYPEOF.OBJECT && q.length > 0) {
|
||||
if (typeof q === OBJ_TYPE && q.length > 0) {
|
||||
if (q.length === 2) {
|
||||
if (typeof q[1] == TYPEOF.FUNCTION) {
|
||||
if (typeof q[1] == FUNC_TYPE) {
|
||||
// assign modified match
|
||||
this[q[0]] = q[1].call(this, match);
|
||||
} else {
|
||||
@@ -249,7 +251,7 @@
|
||||
}
|
||||
} else if (q.length >= 3) {
|
||||
// Check whether q[1] FUNCTION or REGEX
|
||||
if (typeof q[1] === TYPEOF.FUNCTION && !(q[1].exec && q[1].test)) {
|
||||
if (typeof q[1] === FUNC_TYPE && !(q[1].exec && q[1].test)) {
|
||||
if (q.length > 3) {
|
||||
this[q[0]] = match ? q[1].apply(this, q.slice(2)) : undefined;
|
||||
} else {
|
||||
@@ -281,7 +283,7 @@
|
||||
|
||||
for (var i in map) {
|
||||
// check if current value is array
|
||||
if (typeof map[i] === TYPEOF.OBJECT && map[i].length > 0) {
|
||||
if (typeof map[i] === OBJ_TYPE && map[i].length > 0) {
|
||||
for (var j = 0; j < map[i].length; j++) {
|
||||
if (has(map[i][j], str)) {
|
||||
return (i === UNKNOWN) ? undefined : i;
|
||||
@@ -375,11 +377,10 @@
|
||||
/(avant|iemobile|slim(?:browser|boat|jet))[\/ ]?([\d\.]*)/i, // Avant/IEMobile/SlimBrowser/SlimBoat/Slimjet
|
||||
/(?:ms|\()(ie) ([\w\.]+)/i, // Internet Explorer
|
||||
|
||||
// Blink/Webkit/KHTML based // Flock/RockMelt/Midori/Epiphany/Silk/Skyfire/Bolt/Iron/Iridium/PhantomJS/Bowser/QupZilla/Falkon/LG Browser/Otter/qutebrowser/Dooble/Palemoon
|
||||
/(atlas|flock|rockmelt|midori|epiphany|silk|skyfire|ovibrowser|bolt|iron|vivaldi|iridium|phantomjs|bowser|qupzilla|falkon|rekonq|puffin|brave|whale(?!.+naver)|qqbrowserlite|duckduckgo|klar|helio|(?=comodo_)?dragon|otter|dooble|(?:lg |qute)browser|palemoon)\/([-\w\.]+)/i,
|
||||
// Atlas/Rekonq/Puffin/Brave/Whale/QQBrowserLite/QQ//Vivaldi/DuckDuckGo/Klar/Helio/Dragon
|
||||
/(heytap|ovi|115|surf|qwant)browser\/([\d\.]+)/i, // HeyTap/Ovi/115/Surf
|
||||
/(qwant)(?:ios|mobile)\/([\d\.]+)/i, // Qwant
|
||||
// Blink/Webkit/KHTML based // Flock/RockMelt/Midori/Epiphany/Silk/Skyfire/Bolt/Iron/Iridium/PhantomJS/Bowser/QupZilla/Falkon/LG Browser/Otter/qutebrowser/Dooble
|
||||
/(flock|rockmelt|midori|epiphany|silk|skyfire|ovibrowser|bolt|iron|vivaldi|iridium|phantomjs|bowser|qupzilla|falkon|rekonq|puffin|brave|whale(?!.+naver)|qqbrowserlite|duckduckgo|klar|helio|(?=comodo_)?dragon|otter|dooble|(?:lg |qute)browser)\/([-\w\.]+)/i,
|
||||
// Rekonq/Puffin/Brave/Whale/QQBrowserLite/QQ//Vivaldi/DuckDuckGo/Klar/Helio/Dragon
|
||||
/(heytap|ovi|115|surf)browser\/([\d\.]+)/i, // HeyTap/Ovi/115/Surf
|
||||
/(ecosia|weibo)(?:__| \w+@)([\d\.]+)/i // Ecosia/Weibo
|
||||
], [NAME, VERSION], [
|
||||
/quark(?:pc)?\/([-\w\.]+)/i // Quark
|
||||
@@ -432,7 +433,7 @@
|
||||
/(tesla)(?: qtcarbrowser|\/(20\d\d\.[-\w\.]+))/i, // Tesla
|
||||
/m?(qqbrowser|2345(?=browser|chrome|explorer))\w*[\/ ]?v?([\w\.]+)/i // QQ/2345
|
||||
], [NAME, VERSION], [
|
||||
/(lbbrowser|rekonq|steam(?= (clie|tenf|gameo)))/i // LieBao Browser/Rekonq/Steam
|
||||
/(lbbrowser|rekonq)/i // LieBao Browser/Rekonq
|
||||
], [NAME], [
|
||||
/ome\/([\w\.]+) \w* ?(iron) saf/i, // Iron
|
||||
/ome\/([\w\.]+).+qihu (360)[es]e/i // 360
|
||||
@@ -448,7 +449,6 @@
|
||||
/\b(line)\/([\w\.]+)\/iab/i, // Line App for Android
|
||||
/(alipay)client\/([\w\.]+)/i, // Alipay
|
||||
/(twitter)(?:and| f.+e\/([\w\.]+))/i, // Twitter
|
||||
/(bing)(?:web|sapphire)\/([\w\.]+)/i, // Bing
|
||||
/(instagram|snapchat|klarna)[\/ ]([-\w\.]+)/i // Instagram/Snapchat/Klarna
|
||||
], [NAME, VERSION, [TYPE, INAPP]], [
|
||||
/\bgsa\/([\w\.]+) .*safari\//i // Google Search Appliance on iOS
|
||||
@@ -506,10 +506,10 @@
|
||||
/(swiftfox)/i, // Swiftfox
|
||||
/(icedragon|iceweasel|camino|chimera|fennec|maemo browser|minimo|conkeror)[\/ ]?([\w\.\+]+)/i,
|
||||
// IceDragon/Iceweasel/Camino/Chimera/Fennec/Maemo/Minimo/Conkeror
|
||||
/(seamonkey|k-meleon|icecat|iceape|firebird|phoenix|basilisk|waterfox)\/([-\w\.]+)$/i,
|
||||
/(seamonkey|k-meleon|icecat|iceape|firebird|phoenix|palemoon|basilisk|waterfox)\/([-\w\.]+)$/i,
|
||||
// Firefox/SeaMonkey/K-Meleon/IceCat/IceApe/Firebird/Phoenix
|
||||
/(firefox)\/([\w\.]+)/i, // Other Firefox-based
|
||||
/(mozilla)\/([\w\.]+(?= .+rv\:.+gecko\/\d+)|[0-4][\w\.]+(?!.+compatible))/i, // Mozilla
|
||||
/(mozilla)\/([\w\.]+) .+rv\:.+gecko\/\d+/i, // Mozilla
|
||||
|
||||
// Other
|
||||
/(amaya|dillo|doris|icab|ladybird|lynx|mosaic|netsurf|obigo|polaris|w3m|(?:go|ice|up)[\. ]?browser)[-\/ ]?v?([\w\.]+)/i,
|
||||
@@ -547,8 +547,6 @@
|
||||
/((ppc|powerpc)(64)?)( mac|;|\))/i, // PowerPC
|
||||
/(?:osf1|[freopnt]{3,4}bsd) (alpha)/i // Alpha
|
||||
], [[ARCHITECTURE, /ower/, EMPTY, lowerize]], [
|
||||
/mc680.0/i
|
||||
], [[ARCHITECTURE, '68k']], [
|
||||
/winnt.+\[axp/i
|
||||
], [[ARCHITECTURE, 'alpha']]
|
||||
],
|
||||
@@ -568,10 +566,11 @@
|
||||
], [MODEL, [VENDOR, SAMSUNG], [TYPE, MOBILE]], [
|
||||
|
||||
// Apple
|
||||
/(?:\/|\()(ip(?:hone|od)[\w, ]*)[\/\);]/i // iPod/iPhone
|
||||
/(?:\/|\()(ip(?:hone|od)[\w, ]*)(?:\/|;)/i // iPod/iPhone
|
||||
], [MODEL, [VENDOR, APPLE], [TYPE, MOBILE]], [
|
||||
/\b(?:ios|apple\w+)\/.+[\(\/](ipad)/i, // iPad
|
||||
/\b(ipad)[\d,]*[;\] ].+(mac |i(pad)?)os/i
|
||||
/\((ipad);[-\w\),; ]+apple/i, // iPad
|
||||
/applecoremedia\/[\w\.]+ \((ipad)/i,
|
||||
/\b(ipad)\d\d?,\d\d?[;\]].+ios/i
|
||||
], [MODEL, [VENDOR, APPLE], [TYPE, TABLET]], [
|
||||
/(macintosh);/i
|
||||
], [MODEL, [VENDOR, APPLE]], [
|
||||
@@ -589,21 +588,21 @@
|
||||
// Huawei
|
||||
/\b((?:ag[rs][2356]?k?|bah[234]?|bg[2o]|bt[kv]|cmr|cpn|db[ry]2?|jdn2|got|kob2?k?|mon|pce|scm|sht?|[tw]gr|vrd)-[ad]?[lw][0125][09]b?|605hw|bg2-u03|(?:gem|fdr|m2|ple|t1)-[7a]0[1-4][lu]|t1-a2[13][lw]|mediapad[\w\. ]*(?= bui|\)))\b(?!.+d\/s)/i
|
||||
], [MODEL, [VENDOR, HUAWEI], [TYPE, TABLET]], [
|
||||
/(?:huawei) ?([-\w ]+)[;\)]/i,
|
||||
/\b(nexus 6p|\w{2,4}e?-[atu]?[ln][\dx][\dc][adnt]?)\b(?!.+d\/s)/i
|
||||
/(?:huawei)([-\w ]+)[;\)]/i,
|
||||
/\b(nexus 6p|\w{2,4}e?-[atu]?[ln][\dx][012359c][adn]?)\b(?!.+d\/s)/i
|
||||
], [MODEL, [VENDOR, HUAWEI], [TYPE, MOBILE]], [
|
||||
|
||||
// Xiaomi
|
||||
/oid[^\)]+; (2[\dbc]{4}(182|283|rp\w{2})[cgl]|m2105k81a?c)(?: bui|\))/i,
|
||||
/\b(?:xiao)?((?:red)?mi[-_ ]?pad[\w- ]*)(?: bui|\))/i // Mi Pad tablets
|
||||
/\b((?:red)?mi[-_ ]?pad[\w- ]*)(?: bui|\))/i // Mi Pad tablets
|
||||
],[[MODEL, /_/g, ' '], [VENDOR, XIAOMI], [TYPE, TABLET]], [
|
||||
|
||||
/\b(poco[\w ]+|m2\d{3}j\d\d[a-z]{2})(?: bui|\))/i, // Xiaomi POCO
|
||||
/\b; (\w+) build\/hm\1/i, // Xiaomi Hongmi 'numeric' models
|
||||
/\b(hm[-_ ]?note?[_ ]?(?:\d\w)?) bui/i, // Xiaomi Hongmi
|
||||
// Xiaomi Redmi / POCO / Black Shark / Qin
|
||||
/oid[^\)]+; (redmi[\-_ ]?(?:note|k)?[\w_ ]+|m?[12]\d[01]\d\w{3,6}|poco[\w ]+|(shark )?\w{3}-[ah]0|qin ?[1-3](s\+|ultra| pro)?)( bui|; wv|\))/i,
|
||||
// Xiaomi Mi
|
||||
/\b(mi[-_ ]?(?:a\d|one|one[_ ]plus|note|max|cc)?[_ ]?(?:\d{0,2}\w?)[_ ]?(?:plus|se|lite|pro)?( 5g|lte)?)(?: bui|\))/i,
|
||||
/\b(redmi[\-_ ]?(?:note|k)?[\w_ ]+)(?: bui|\))/i, // Xiaomi Redmi
|
||||
/oid[^\)]+; (m?[12][0-389][01]\w{3,6}[c-y])( bui|; wv|\))/i, // Xiaomi Redmi 'numeric' models
|
||||
/\b(mi[-_ ]?(?:a\d|one|one[_ ]plus|note lte|max|cc)?[_ ]?(?:\d?\w?)[_ ]?(?:plus|se|lite|pro)?)(?: bui|\))/i, // Xiaomi Mi
|
||||
/ ([\w ]+) miui\/v?\d/i
|
||||
], [[MODEL, /_/g, ' '], [VENDOR, XIAOMI], [TYPE, MOBILE]], [
|
||||
|
||||
@@ -659,7 +658,7 @@
|
||||
/(nokia) (t[12][01])/i
|
||||
], [VENDOR, MODEL, [TYPE, TABLET]], [
|
||||
/(?:maemo|nokia).*(n900|lumia \d+|rm-\d+)/i,
|
||||
/nokia[-_ ]?(([-\w\. ]*?))( bui|\)|;|\/)/i
|
||||
/nokia[-_ ]?(([-\w\. ]*))/i
|
||||
], [[MODEL, /_/g, ' '], [TYPE, MOBILE], [VENDOR, 'Nokia']], [
|
||||
|
||||
// Google
|
||||
@@ -690,7 +689,7 @@
|
||||
/(playbook);[-\w\),; ]+(rim)/i // BlackBerry PlayBook
|
||||
], [MODEL, VENDOR, [TYPE, TABLET]], [
|
||||
/\b((?:bb[a-f]|st[hv])100-\d)/i,
|
||||
/(?:blackberry|\(bb10;) (\w+)/i
|
||||
/\(bb10; (\w+)/i // BlackBerry 10
|
||||
], [MODEL, [VENDOR, BLACKBERRY], [TYPE, MOBILE]], [
|
||||
|
||||
// Asus
|
||||
@@ -770,12 +769,10 @@
|
||||
|
||||
/(blackberry|benq|palm(?=\-)|sonyericsson|acer|asus(?! zenw)|dell|jolla|meizu|motorola|polytron|tecno|micromax|advan)[-_ ]?([-\w]*)/i,
|
||||
// BlackBerry/BenQ/Palm/Sony-Ericsson/Acer/Asus/Dell/Meizu/Motorola/Polytron/Tecno/Micromax/Advan
|
||||
// BLU/HMD/IMO/Infinix/Lava/OnePlus/TCL/Wiko
|
||||
/; (blu|hmd|imo|infinix|lava|oneplus|tcl|wiko)[_ ]([\w\+ ]+?)(?: bui|\)|; r)/i,
|
||||
/; (blu|hmd|imo|infinix|lava|oneplus|tcl)[_ ]([\w\+ ]+?)(?: bui|\)|; r)/i, // BLU/HMD/IMO/Infinix/Lava/OnePlus/TCL
|
||||
/(hp) ([\w ]+\w)/i, // HP iPAQ
|
||||
/(microsoft); (lumia[\w ]+)/i, // Microsoft Lumia
|
||||
/(oppo) ?([\w ]+) bui/i, // OPPO
|
||||
/(hisense) ([ehv][\w ]+)\)/i, // Hisense
|
||||
/droid[^;]+; (philips)[_ ]([sv-x][\d]{3,4}[xz]?)/i // Philips
|
||||
], [VENDOR, MODEL, [TYPE, MOBILE]], [
|
||||
|
||||
@@ -852,10 +849,10 @@
|
||||
], [MODEL, [VENDOR, MICROSOFT], [TYPE, CONSOLE]], [
|
||||
/(ouya)/i, // Ouya
|
||||
/(nintendo) (\w+)/i, // Nintendo
|
||||
/(retroid) (pocket ([^\)]+))/i, // Retroid Pocket
|
||||
/(valve).+(steam deck)/i,
|
||||
/droid.+; ((shield|rgcube|gr0006))( bui|\))/i // Nvidia Portable/Anbernic/Logitech
|
||||
], [[VENDOR, strMapper, { 'Nvidia': 'Shield', 'Anbernic': 'RGCUBE', 'Logitech': 'GR0006' }], MODEL, [TYPE, CONSOLE]], [
|
||||
/(retroid) (pocket ([^\)]+))/i // Retroid Pocket
|
||||
], [VENDOR, MODEL, [TYPE, CONSOLE]], [
|
||||
/droid.+; (shield)( bui|\))/i // Nvidia Portable
|
||||
], [MODEL, [VENDOR, NVIDIA], [TYPE, CONSOLE]], [
|
||||
|
||||
///////////////////
|
||||
// WEARABLES
|
||||
@@ -864,7 +861,7 @@
|
||||
/\b(sm-[lr]\d\d[0156][fnuw]?s?|gear live)\b/i // Samsung Galaxy Watch
|
||||
], [MODEL, [VENDOR, SAMSUNG], [TYPE, WEARABLE]], [
|
||||
/((pebble))app/i, // Pebble
|
||||
/(asus|google|lg|oppo|xiaomi) ((pixel |zen)?watch[\w ]*)( bui|\))/i // Asus ZenWatch / LG Watch / Pixel Watch / Xiaomi Watch
|
||||
/(asus|google|lg|oppo) ((pixel |zen)?watch[\w ]*)( bui|\))/i // Asus ZenWatch / LG Watch / Pixel Watch
|
||||
], [VENDOR, MODEL, [TYPE, WEARABLE]], [
|
||||
/(ow(?:19|20)?we?[1-3]{1,3})/i // Oppo Watch
|
||||
], [MODEL, [VENDOR, OPPO], [TYPE, WEARABLE]], [
|
||||
@@ -915,7 +912,7 @@
|
||||
], [MODEL, [TYPE, SMARTTV]], [
|
||||
/\b((4k|android|smart|opera)[- ]?tv|tv; rv:|large screen[\w ]+safari)\b/i
|
||||
], [[TYPE, SMARTTV]], [
|
||||
/droid .+?; ([^;]+?)(?: bui|; wv\)|\) applew|; hmsc).+?(mobile|vr|\d) safari/i
|
||||
/droid .+?; ([^;]+?)(?: bui|; wv\)|\) applew).+?(mobile|vr|\d) safari/i
|
||||
], [MODEL, [TYPE, strMapper, { 'mobile' : 'Mobile', 'xr' : 'VR', '*' : TABLET }]], [
|
||||
/\b((tablet|tab)[;\/]|focus\/\d(?!.+mobile))/i // Unidentifiable Tablet
|
||||
], [[TYPE, TABLET]], [
|
||||
@@ -968,8 +965,7 @@
|
||||
|
||||
// iOS/macOS
|
||||
/[adehimnop]{4,7}\b(?:.*os ([\w]+) like mac|; opera)/i, // iOS
|
||||
/(?:ios;fbsv|ios(?=.+ip(?:ad|hone)|.+apple ?tv)|ip(?:ad|hone)(?: |.+i(?:pad)?)os|apple ?tv.+ios)[\/ ]([\w\.]+)/i,
|
||||
/\btvos ?([\w\.]+)/i,
|
||||
/(?:ios;fbsv\/|iphone.+ios[\/ ])([\d\.]+)/i,
|
||||
/cfnetwork\/.+darwin/i
|
||||
], [[VERSION, /_/g, '.'], [NAME, 'iOS']], [
|
||||
/(mac os x) ?([\w\. ]*)/i,
|
||||
@@ -1054,27 +1050,27 @@
|
||||
var defaultProps = (function () {
|
||||
var props = { init : {}, isIgnore : {}, isIgnoreRgx : {}, toString : {}};
|
||||
setProps.call(props.init, [
|
||||
[BROWSER, [NAME, VERSION, MAJOR, TYPE]],
|
||||
[CPU, [ARCHITECTURE]],
|
||||
[DEVICE, [TYPE, MODEL, VENDOR]],
|
||||
[ENGINE, [NAME, VERSION]],
|
||||
[OS, [NAME, VERSION]]
|
||||
[UA_BROWSER, [NAME, VERSION, MAJOR, TYPE]],
|
||||
[UA_CPU, [ARCHITECTURE]],
|
||||
[UA_DEVICE, [TYPE, MODEL, VENDOR]],
|
||||
[UA_ENGINE, [NAME, VERSION]],
|
||||
[UA_OS, [NAME, VERSION]]
|
||||
]);
|
||||
setProps.call(props.isIgnore, [
|
||||
[BROWSER, [VERSION, MAJOR]],
|
||||
[ENGINE, [VERSION]],
|
||||
[OS, [VERSION]]
|
||||
[UA_BROWSER, [VERSION, MAJOR]],
|
||||
[UA_ENGINE, [VERSION]],
|
||||
[UA_OS, [VERSION]]
|
||||
]);
|
||||
setProps.call(props.isIgnoreRgx, [
|
||||
[BROWSER, / ?browser$/i],
|
||||
[OS, / ?os$/i]
|
||||
[UA_BROWSER, / ?browser$/i],
|
||||
[UA_OS, / ?os$/i]
|
||||
]);
|
||||
setProps.call(props.toString, [
|
||||
[BROWSER, [NAME, VERSION]],
|
||||
[CPU, [ARCHITECTURE]],
|
||||
[DEVICE, [VENDOR, MODEL]],
|
||||
[ENGINE, [NAME, VERSION]],
|
||||
[OS, [NAME, VERSION]]
|
||||
[UA_BROWSER, [NAME, VERSION]],
|
||||
[UA_CPU, [ARCHITECTURE]],
|
||||
[UA_DEVICE, [VENDOR, MODEL]],
|
||||
[UA_ENGINE, [NAME, VERSION]],
|
||||
[UA_OS, [NAME, VERSION]]
|
||||
]);
|
||||
return props;
|
||||
})();
|
||||
@@ -1118,14 +1114,14 @@
|
||||
return item.detectFeature().get();
|
||||
};
|
||||
|
||||
if (itemType != RESULT) {
|
||||
if (itemType != UA_RESULT) {
|
||||
IData.prototype.is = function (strToCheck) {
|
||||
var is = false;
|
||||
for (var i in this) {
|
||||
if (this.hasOwnProperty(i) && !has(is_ignoreProps, i) && lowerize(is_ignoreRgx ? strip(is_ignoreRgx, this[i]) : this[i]) == lowerize(is_ignoreRgx ? strip(is_ignoreRgx, strToCheck) : strToCheck)) {
|
||||
is = true;
|
||||
if (strToCheck != TYPEOF.UNDEFINED) break;
|
||||
} else if (strToCheck == TYPEOF.UNDEFINED && is) {
|
||||
if (strToCheck != UNDEF_TYPE) break;
|
||||
} else if (strToCheck == UNDEF_TYPE && is) {
|
||||
is = !is;
|
||||
break;
|
||||
}
|
||||
@@ -1135,14 +1131,15 @@
|
||||
IData.prototype.toString = function () {
|
||||
var str = EMPTY;
|
||||
for (var i in toString_props) {
|
||||
if (typeof(this[toString_props[i]]) !== TYPEOF.UNDEFINED) {
|
||||
if (typeof(this[toString_props[i]]) !== UNDEF_TYPE) {
|
||||
str += (str ? ' ' : EMPTY) + this[toString_props[i]];
|
||||
}
|
||||
}
|
||||
return str || TYPEOF.UNDEFINED;
|
||||
return str || UNDEF_TYPE;
|
||||
};
|
||||
}
|
||||
|
||||
if (!NAVIGATOR_UADATA) {
|
||||
IData.prototype.then = function (cb) {
|
||||
var that = this;
|
||||
var IDataResolve = function () {
|
||||
@@ -1154,14 +1151,13 @@
|
||||
};
|
||||
IDataResolve.prototype = {
|
||||
is : IData.prototype.is,
|
||||
toString : IData.prototype.toString,
|
||||
withClientHints : IData.prototype.withClientHints,
|
||||
withFeatureCheck : IData.prototype.withFeatureCheck
|
||||
toString : IData.prototype.toString
|
||||
};
|
||||
var resolveData = new IDataResolve();
|
||||
cb(resolveData);
|
||||
return resolveData;
|
||||
};
|
||||
}
|
||||
|
||||
return new IData();
|
||||
};
|
||||
@@ -1175,76 +1171,67 @@
|
||||
setProps.call(this, CH_ALL_VALUES);
|
||||
if (isHttpUACH) {
|
||||
setProps.call(this, [
|
||||
[BRANDS, itemListToArray(uach[CH])],
|
||||
[FULLVERLIST, itemListToArray(uach[CH_FULL_VER_LIST])],
|
||||
[MOBILE, /\?1/.test(uach[CH_MOBILE])],
|
||||
[MODEL, stripQuotes(uach[CH_MODEL])],
|
||||
[PLATFORM, stripQuotes(uach[CH_PLATFORM])],
|
||||
[PLATFORMVER, stripQuotes(uach[CH_PLATFORM_VER])],
|
||||
[ARCHITECTURE, stripQuotes(uach[CH_ARCH])],
|
||||
[FORMFACTORS, itemListToArray(uach[CH_FORM_FACTORS])],
|
||||
[BITNESS, stripQuotes(uach[CH_BITNESS])]
|
||||
[BRANDS, itemListToArray(uach[CH_HEADER])],
|
||||
[FULLVERLIST, itemListToArray(uach[CH_HEADER_FULL_VER_LIST])],
|
||||
[MOBILE, /\?1/.test(uach[CH_HEADER_MOBILE])],
|
||||
[MODEL, stripQuotes(uach[CH_HEADER_MODEL])],
|
||||
[PLATFORM, stripQuotes(uach[CH_HEADER_PLATFORM])],
|
||||
[PLATFORMVER, stripQuotes(uach[CH_HEADER_PLATFORM_VER])],
|
||||
[ARCHITECTURE, stripQuotes(uach[CH_HEADER_ARCH])],
|
||||
[FORMFACTORS, itemListToArray(uach[CH_HEADER_FORM_FACTORS])],
|
||||
[BITNESS, stripQuotes(uach[CH_HEADER_BITNESS])]
|
||||
]);
|
||||
} else {
|
||||
for (var prop in uach) {
|
||||
if(this.hasOwnProperty(prop) && typeof uach[prop] !== TYPEOF.UNDEFINED) this[prop] = uach[prop];
|
||||
if(this.hasOwnProperty(prop) && typeof uach[prop] !== UNDEF_TYPE) this[prop] = uach[prop];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function UAItem (itemType, ua, rgxMap, uaCH) {
|
||||
setProps.call(this, [
|
||||
['itemType', itemType],
|
||||
['ua', ua],
|
||||
['uaCH', uaCH],
|
||||
['rgxMap', rgxMap],
|
||||
['data', createIData(this, itemType)]
|
||||
]);
|
||||
return this;
|
||||
}
|
||||
|
||||
UAItem.prototype.get = function (prop) {
|
||||
this.get = function (prop) {
|
||||
if (!prop) return this.data;
|
||||
return this.data.hasOwnProperty(prop) ? this.data[prop] : undefined;
|
||||
};
|
||||
|
||||
UAItem.prototype.set = function (prop, val) {
|
||||
this.set = function (prop, val) {
|
||||
this.data[prop] = val;
|
||||
return this;
|
||||
};
|
||||
|
||||
UAItem.prototype.setCH = function (ch) {
|
||||
this.setCH = function (ch) {
|
||||
this.uaCH = ch;
|
||||
return this;
|
||||
};
|
||||
|
||||
UAItem.prototype.detectFeature = function () {
|
||||
this.detectFeature = function () {
|
||||
if (NAVIGATOR && NAVIGATOR.userAgent == this.ua) {
|
||||
switch (this.itemType) {
|
||||
case BROWSER:
|
||||
case UA_BROWSER:
|
||||
// Brave-specific detection
|
||||
if (NAVIGATOR.brave && typeof NAVIGATOR.brave.isBrave == TYPEOF.FUNCTION) {
|
||||
if (NAVIGATOR.brave && typeof NAVIGATOR.brave.isBrave == FUNC_TYPE) {
|
||||
this.set(NAME, 'Brave');
|
||||
}
|
||||
break;
|
||||
case DEVICE:
|
||||
case UA_DEVICE:
|
||||
// Chrome-specific detection: check for 'mobile' value of navigator.userAgentData
|
||||
if (!this.get(TYPE) && NAVIGATOR_UADATA && NAVIGATOR_UADATA[MOBILE]) {
|
||||
this.set(TYPE, MOBILE);
|
||||
}
|
||||
// iPadOS-specific detection: identified as Mac, but has some iOS-only properties
|
||||
if (this.get(MODEL) == 'Macintosh' && NAVIGATOR && typeof NAVIGATOR.standalone !== TYPEOF.UNDEFINED && NAVIGATOR.maxTouchPoints && NAVIGATOR.maxTouchPoints > 2) {
|
||||
if (this.get(MODEL) == 'Macintosh' && NAVIGATOR && typeof NAVIGATOR.standalone !== UNDEF_TYPE && NAVIGATOR.maxTouchPoints && NAVIGATOR.maxTouchPoints > 2) {
|
||||
this.set(MODEL, 'iPad')
|
||||
.set(TYPE, TABLET);
|
||||
}
|
||||
break;
|
||||
case OS:
|
||||
case UA_OS:
|
||||
// Chrome-specific detection: check for 'platform' value of navigator.userAgentData
|
||||
if (!this.get(NAME) && NAVIGATOR_UADATA && NAVIGATOR_UADATA[PLATFORM]) {
|
||||
this.set(NAME, NAVIGATOR_UADATA[PLATFORM]);
|
||||
}
|
||||
break;
|
||||
case RESULT:
|
||||
case UA_RESULT:
|
||||
var data = this.data;
|
||||
var detect = function (itemType) {
|
||||
return data[itemType]
|
||||
@@ -1252,50 +1239,39 @@
|
||||
.detectFeature()
|
||||
.get();
|
||||
};
|
||||
this.set(BROWSER, detect(BROWSER))
|
||||
.set(CPU, detect(CPU))
|
||||
.set(DEVICE, detect(DEVICE))
|
||||
.set(ENGINE, detect(ENGINE))
|
||||
.set(OS, detect(OS));
|
||||
this.set(UA_BROWSER, detect(UA_BROWSER))
|
||||
.set(UA_CPU, detect(UA_CPU))
|
||||
.set(UA_DEVICE, detect(UA_DEVICE))
|
||||
.set(UA_ENGINE, detect(UA_ENGINE))
|
||||
.set(UA_OS, detect(UA_OS));
|
||||
}
|
||||
}
|
||||
return this;
|
||||
};
|
||||
|
||||
UAItem.prototype.parseUA = function () {
|
||||
if (this.itemType != RESULT) {
|
||||
this.parseUA = function () {
|
||||
if (this.itemType != UA_RESULT) {
|
||||
rgxMapper.call(this.data, this.ua, this.rgxMap);
|
||||
}
|
||||
switch (this.itemType) {
|
||||
case BROWSER:
|
||||
if (this.itemType == UA_BROWSER) {
|
||||
this.set(MAJOR, majorize(this.get(VERSION)));
|
||||
break;
|
||||
case OS:
|
||||
if (this.get(NAME) == 'iOS' && this.get(VERSION) == '18.6') {
|
||||
// Based on the assumption that iOS version is tightly coupled with Safari version
|
||||
var realVersion = /\) Version\/([\d\.]+)/.exec(this.ua); // Get Safari version
|
||||
if (realVersion && parseInt(realVersion[1].substring(0,2), 10) >= 26) {
|
||||
this.set(VERSION, realVersion[1]); // Set as iOS version
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
return this;
|
||||
};
|
||||
|
||||
UAItem.prototype.parseCH = function () {
|
||||
this.parseCH = function () {
|
||||
var uaCH = this.uaCH,
|
||||
rgxMap = this.rgxMap;
|
||||
|
||||
switch (this.itemType) {
|
||||
case BROWSER:
|
||||
case ENGINE:
|
||||
case UA_BROWSER:
|
||||
case UA_ENGINE:
|
||||
var brands = uaCH[FULLVERLIST] || uaCH[BRANDS], prevName;
|
||||
if (brands) {
|
||||
for (var i=0; i<brands.length; i++) {
|
||||
var brandName = brands[i].brand || brands[i],
|
||||
brandVersion = brands[i].version;
|
||||
if (this.itemType == BROWSER &&
|
||||
if (this.itemType == UA_BROWSER &&
|
||||
!/not.a.brand/i.test(brandName) &&
|
||||
(!prevName ||
|
||||
(/Chrom/.test(prevName) && brandName != CHROMIUM) ||
|
||||
@@ -1310,20 +1286,20 @@
|
||||
}
|
||||
prevName = brandName;
|
||||
}
|
||||
if (this.itemType == ENGINE && brandName == CHROMIUM) {
|
||||
if (this.itemType == UA_ENGINE && brandName == CHROMIUM) {
|
||||
this.set(VERSION, brandVersion);
|
||||
}
|
||||
}
|
||||
}
|
||||
break;
|
||||
case CPU:
|
||||
case UA_CPU:
|
||||
var archName = uaCH[ARCHITECTURE];
|
||||
if (archName) {
|
||||
if (archName && uaCH[BITNESS] == '64') archName += '64';
|
||||
rgxMapper.call(this.data, archName + ';', rgxMap);
|
||||
}
|
||||
break;
|
||||
case DEVICE:
|
||||
case UA_DEVICE:
|
||||
if (uaCH[MOBILE]) {
|
||||
this.set(TYPE, MOBILE);
|
||||
}
|
||||
@@ -1353,7 +1329,7 @@
|
||||
this.set(TYPE, ff);
|
||||
}
|
||||
break;
|
||||
case OS:
|
||||
case UA_OS:
|
||||
var osName = uaCH[PLATFORM];
|
||||
if(osName) {
|
||||
var osVersion = uaCH[PLATFORMVER];
|
||||
@@ -1367,7 +1343,7 @@
|
||||
.set(VERSION, undefined);
|
||||
}
|
||||
break;
|
||||
case RESULT:
|
||||
case UA_RESULT:
|
||||
var data = this.data;
|
||||
var parse = function (itemType) {
|
||||
return data[itemType]
|
||||
@@ -1376,20 +1352,31 @@
|
||||
.parseCH()
|
||||
.get();
|
||||
};
|
||||
this.set(BROWSER, parse(BROWSER))
|
||||
.set(CPU, parse(CPU))
|
||||
.set(DEVICE, parse(DEVICE))
|
||||
.set(ENGINE, parse(ENGINE))
|
||||
.set(OS, parse(OS));
|
||||
this.set(UA_BROWSER, parse(UA_BROWSER))
|
||||
.set(UA_CPU, parse(UA_CPU))
|
||||
.set(UA_DEVICE, parse(UA_DEVICE))
|
||||
.set(UA_ENGINE, parse(UA_ENGINE))
|
||||
.set(UA_OS, parse(UA_OS));
|
||||
}
|
||||
return this;
|
||||
};
|
||||
|
||||
setProps.call(this, [
|
||||
['itemType', itemType],
|
||||
['ua', ua],
|
||||
['uaCH', uaCH],
|
||||
['rgxMap', rgxMap],
|
||||
['data', createIData(this, itemType)]
|
||||
]);
|
||||
|
||||
return this;
|
||||
}
|
||||
|
||||
function UAParser (ua, extensions, headers) {
|
||||
|
||||
if (typeof ua === TYPEOF.OBJECT) {
|
||||
if (typeof ua === OBJ_TYPE) {
|
||||
if (isExtensions(ua, true)) {
|
||||
if (typeof extensions === TYPEOF.OBJECT) {
|
||||
if (typeof extensions === OBJ_TYPE) {
|
||||
headers = extensions; // case UAParser(extensions, headers)
|
||||
}
|
||||
extensions = ua; // case UAParser(extensions)
|
||||
@@ -1398,13 +1385,13 @@
|
||||
extensions = undefined;
|
||||
}
|
||||
ua = undefined;
|
||||
} else if (typeof ua === TYPEOF.STRING && !isExtensions(extensions, true)) {
|
||||
} else if (typeof ua === STR_TYPE && !isExtensions(extensions, true)) {
|
||||
headers = extensions; // case UAParser(ua, headers)
|
||||
extensions = undefined;
|
||||
}
|
||||
|
||||
if (headers) {
|
||||
if (typeof headers.append === TYPEOF.FUNCTION) {
|
||||
if (typeof headers.append === FUNC_TYPE) {
|
||||
// Convert Headers object into a plain object
|
||||
var kv = {};
|
||||
headers.forEach(function (v, k) { kv[String(k).toLowerCase()] = v; });
|
||||
@@ -1425,7 +1412,7 @@
|
||||
return new UAParser(ua, extensions, headers).getResult();
|
||||
}
|
||||
|
||||
var userAgent = typeof ua === TYPEOF.STRING ? ua : // Passed user-agent string
|
||||
var userAgent = typeof ua === STR_TYPE ? ua : // Passed user-agent string
|
||||
(headers && headers[USER_AGENT] ? headers[USER_AGENT] : // User-Agent from passed headers
|
||||
((NAVIGATOR && NAVIGATOR.userAgent) ? NAVIGATOR.userAgent : // navigator.userAgent
|
||||
EMPTY)), // empty string
|
||||
@@ -1436,15 +1423,15 @@
|
||||
defaultRegexes,
|
||||
|
||||
createItemFunc = function (itemType) {
|
||||
if (itemType == RESULT) {
|
||||
if (itemType == UA_RESULT) {
|
||||
return function () {
|
||||
return new UAItem(itemType, userAgent, regexMap, httpUACH)
|
||||
.set('ua', userAgent)
|
||||
.set(BROWSER, this.getBrowser())
|
||||
.set(CPU, this.getCPU())
|
||||
.set(DEVICE, this.getDevice())
|
||||
.set(ENGINE, this.getEngine())
|
||||
.set(OS, this.getOS())
|
||||
.set(UA_BROWSER, this.getBrowser())
|
||||
.set(UA_CPU, this.getCPU())
|
||||
.set(UA_DEVICE, this.getDevice())
|
||||
.set(UA_ENGINE, this.getEngine())
|
||||
.set(UA_OS, this.getOS())
|
||||
.get();
|
||||
};
|
||||
} else {
|
||||
@@ -1458,15 +1445,16 @@
|
||||
|
||||
// public methods
|
||||
setProps.call(this, [
|
||||
['getBrowser', createItemFunc(BROWSER)],
|
||||
['getCPU', createItemFunc(CPU)],
|
||||
['getDevice', createItemFunc(DEVICE)],
|
||||
['getEngine', createItemFunc(ENGINE)],
|
||||
['getOS', createItemFunc(OS)],
|
||||
['getResult', createItemFunc(RESULT)],
|
||||
['getBrowser', createItemFunc(UA_BROWSER)],
|
||||
['getCPU', createItemFunc(UA_CPU)],
|
||||
['getDevice', createItemFunc(UA_DEVICE)],
|
||||
['getEngine', createItemFunc(UA_ENGINE)],
|
||||
['getOS', createItemFunc(UA_OS)],
|
||||
['getResult', createItemFunc(UA_RESULT)],
|
||||
['getUA', function () { return userAgent; }],
|
||||
['setUA', function (ua) {
|
||||
if (isString(ua)) userAgent = trim(ua, UA_MAX_LENGTH);
|
||||
if (isString(ua))
|
||||
userAgent = ua.length > UA_MAX_LENGTH ? trim(ua, UA_MAX_LENGTH) : ua;
|
||||
return this;
|
||||
}]
|
||||
])
|
||||
@@ -1486,15 +1474,15 @@
|
||||
//////////
|
||||
|
||||
// check js environment
|
||||
if (typeof exports !== TYPEOF.UNDEFINED) {
|
||||
if (typeof exports !== UNDEF_TYPE) {
|
||||
// nodejs env
|
||||
if (typeof module !== TYPEOF.UNDEFINED && module.exports) {
|
||||
if (typeof module !== UNDEF_TYPE && module.exports) {
|
||||
exports = module.exports = UAParser;
|
||||
}
|
||||
exports.UAParser = UAParser;
|
||||
} else {
|
||||
// requirejs env (optional)
|
||||
if (typeof define === TYPEOF.FUNCTION && define.amd) {
|
||||
if (typeof define === FUNC_TYPE && define.amd) {
|
||||
define(function () {
|
||||
return UAParser;
|
||||
});
|
||||
|
||||
@@ -3,9 +3,9 @@
|
||||
// Source: /src/main/ua-parser.js
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////////////
|
||||
/* UAParser.js v2.0.7
|
||||
/* UAParser.js v2.0.5
|
||||
Copyright © 2012-2025 Faisal Salman <f@faisalman.com>
|
||||
AGPLv3 License *//*
|
||||
UAParser.js PRO Personal License *//*
|
||||
Detect Browser, Engine, OS, CPU, and Device type/model from User-Agent data.
|
||||
Supports browser & node.js environment.
|
||||
Demo : https://uaparser.dev
|
||||
@@ -21,25 +21,25 @@
|
||||
// Constants
|
||||
/////////////
|
||||
|
||||
var LIBVERSION = '2.0.7',
|
||||
var LIBVERSION = '2.0.5',
|
||||
UA_MAX_LENGTH = 500,
|
||||
USER_AGENT = 'user-agent',
|
||||
EMPTY = '',
|
||||
UNKNOWN = '?',
|
||||
TYPEOF = {
|
||||
FUNCTION : 'function',
|
||||
OBJECT : 'object',
|
||||
STRING : 'string',
|
||||
UNDEFINED : 'undefined'
|
||||
},
|
||||
|
||||
// typeof
|
||||
FUNC_TYPE = 'function',
|
||||
UNDEF_TYPE = 'undefined',
|
||||
OBJ_TYPE = 'object',
|
||||
STR_TYPE = 'string',
|
||||
|
||||
// properties
|
||||
BROWSER = 'browser',
|
||||
CPU = 'cpu',
|
||||
DEVICE = 'device',
|
||||
ENGINE = 'engine',
|
||||
OS = 'os',
|
||||
RESULT = 'result',
|
||||
UA_BROWSER = 'browser',
|
||||
UA_CPU = 'cpu',
|
||||
UA_DEVICE = 'device',
|
||||
UA_ENGINE = 'engine',
|
||||
UA_OS = 'os',
|
||||
UA_RESULT = 'result',
|
||||
|
||||
NAME = 'name',
|
||||
TYPE = 'type',
|
||||
@@ -68,15 +68,15 @@
|
||||
PLATFORM = 'platform',
|
||||
PLATFORMVER = 'platformVersion',
|
||||
BITNESS = 'bitness',
|
||||
CH = 'sec-ch-ua',
|
||||
CH_FULL_VER_LIST= CH + '-full-version-list',
|
||||
CH_ARCH = CH + '-arch',
|
||||
CH_BITNESS = CH + '-' + BITNESS,
|
||||
CH_FORM_FACTORS = CH + '-form-factors',
|
||||
CH_MOBILE = CH + '-' + MOBILE,
|
||||
CH_MODEL = CH + '-' + MODEL,
|
||||
CH_PLATFORM = CH + '-' + PLATFORM,
|
||||
CH_PLATFORM_VER = CH_PLATFORM + '-version',
|
||||
CH_HEADER = 'sec-ch-ua',
|
||||
CH_HEADER_FULL_VER_LIST = CH_HEADER + '-full-version-list',
|
||||
CH_HEADER_ARCH = CH_HEADER + '-arch',
|
||||
CH_HEADER_BITNESS = CH_HEADER + '-' + BITNESS,
|
||||
CH_HEADER_FORM_FACTORS = CH_HEADER + '-form-factors',
|
||||
CH_HEADER_MOBILE = CH_HEADER + '-' + MOBILE,
|
||||
CH_HEADER_MODEL = CH_HEADER + '-' + MODEL,
|
||||
CH_HEADER_PLATFORM = CH_HEADER + '-' + PLATFORM,
|
||||
CH_HEADER_PLATFORM_VER = CH_HEADER_PLATFORM + '-version',
|
||||
CH_ALL_VALUES = [BRANDS, FULLVERLIST, MOBILE, MODEL, PLATFORM, PLATFORMVER, ARCHITECTURE, FORMFACTORS, BITNESS],
|
||||
|
||||
// device vendors
|
||||
@@ -116,7 +116,7 @@
|
||||
// os
|
||||
WINDOWS = 'Windows';
|
||||
|
||||
var isWindow = typeof window !== TYPEOF.UNDEFINED,
|
||||
var isWindow = typeof window !== UNDEF_TYPE,
|
||||
NAVIGATOR = (isWindow && window.navigator) ?
|
||||
window.navigator :
|
||||
undefined,
|
||||
@@ -152,7 +152,7 @@
|
||||
return enums;
|
||||
},
|
||||
has = function (str1, str2) {
|
||||
if (typeof str1 === TYPEOF.OBJECT && str1.length > 0) {
|
||||
if (typeof str1 === OBJ_TYPE && str1.length > 0) {
|
||||
for (var i in str1) {
|
||||
if (lowerize(str2) == lowerize(str1[i])) return true;
|
||||
}
|
||||
@@ -166,7 +166,7 @@
|
||||
}
|
||||
},
|
||||
isString = function (val) {
|
||||
return typeof val === TYPEOF.STRING;
|
||||
return typeof val === STR_TYPE;
|
||||
},
|
||||
itemListToArray = function (header) {
|
||||
if (!header) return undefined;
|
||||
@@ -193,7 +193,7 @@
|
||||
if (!arr.hasOwnProperty(i)) continue;
|
||||
|
||||
var propName = arr[i];
|
||||
if (typeof propName == TYPEOF.OBJECT && propName.length == 2) {
|
||||
if (typeof propName == OBJ_TYPE && propName.length == 2) {
|
||||
this[propName[0]] = propName[1];
|
||||
} else {
|
||||
this[propName] = undefined;
|
||||
@@ -208,8 +208,10 @@
|
||||
return strip(/\\?\"/g, str);
|
||||
},
|
||||
trim = function (str, len) {
|
||||
str = strip(/^\s\s*/, String(str));
|
||||
return typeof len === TYPEOF.UNDEFINED ? str : str.substring(0, len);
|
||||
if (isString(str)) {
|
||||
str = strip(/^\s\s*/, str);
|
||||
return typeof len === UNDEF_TYPE ? str : str.substring(0, UA_MAX_LENGTH);
|
||||
}
|
||||
};
|
||||
|
||||
///////////////
|
||||
@@ -240,9 +242,9 @@
|
||||
match = matches[++k];
|
||||
q = props[p];
|
||||
// check if given property is actually array
|
||||
if (typeof q === TYPEOF.OBJECT && q.length > 0) {
|
||||
if (typeof q === OBJ_TYPE && q.length > 0) {
|
||||
if (q.length === 2) {
|
||||
if (typeof q[1] == TYPEOF.FUNCTION) {
|
||||
if (typeof q[1] == FUNC_TYPE) {
|
||||
// assign modified match
|
||||
this[q[0]] = q[1].call(this, match);
|
||||
} else {
|
||||
@@ -251,7 +253,7 @@
|
||||
}
|
||||
} else if (q.length >= 3) {
|
||||
// Check whether q[1] FUNCTION or REGEX
|
||||
if (typeof q[1] === TYPEOF.FUNCTION && !(q[1].exec && q[1].test)) {
|
||||
if (typeof q[1] === FUNC_TYPE && !(q[1].exec && q[1].test)) {
|
||||
if (q.length > 3) {
|
||||
this[q[0]] = match ? q[1].apply(this, q.slice(2)) : undefined;
|
||||
} else {
|
||||
@@ -283,7 +285,7 @@
|
||||
|
||||
for (var i in map) {
|
||||
// check if current value is array
|
||||
if (typeof map[i] === TYPEOF.OBJECT && map[i].length > 0) {
|
||||
if (typeof map[i] === OBJ_TYPE && map[i].length > 0) {
|
||||
for (var j = 0; j < map[i].length; j++) {
|
||||
if (has(map[i][j], str)) {
|
||||
return (i === UNKNOWN) ? undefined : i;
|
||||
@@ -377,11 +379,10 @@
|
||||
/(avant|iemobile|slim(?:browser|boat|jet))[\/ ]?([\d\.]*)/i, // Avant/IEMobile/SlimBrowser/SlimBoat/Slimjet
|
||||
/(?:ms|\()(ie) ([\w\.]+)/i, // Internet Explorer
|
||||
|
||||
// Blink/Webkit/KHTML based // Flock/RockMelt/Midori/Epiphany/Silk/Skyfire/Bolt/Iron/Iridium/PhantomJS/Bowser/QupZilla/Falkon/LG Browser/Otter/qutebrowser/Dooble/Palemoon
|
||||
/(atlas|flock|rockmelt|midori|epiphany|silk|skyfire|ovibrowser|bolt|iron|vivaldi|iridium|phantomjs|bowser|qupzilla|falkon|rekonq|puffin|brave|whale(?!.+naver)|qqbrowserlite|duckduckgo|klar|helio|(?=comodo_)?dragon|otter|dooble|(?:lg |qute)browser|palemoon)\/([-\w\.]+)/i,
|
||||
// Atlas/Rekonq/Puffin/Brave/Whale/QQBrowserLite/QQ//Vivaldi/DuckDuckGo/Klar/Helio/Dragon
|
||||
/(heytap|ovi|115|surf|qwant)browser\/([\d\.]+)/i, // HeyTap/Ovi/115/Surf
|
||||
/(qwant)(?:ios|mobile)\/([\d\.]+)/i, // Qwant
|
||||
// Blink/Webkit/KHTML based // Flock/RockMelt/Midori/Epiphany/Silk/Skyfire/Bolt/Iron/Iridium/PhantomJS/Bowser/QupZilla/Falkon/LG Browser/Otter/qutebrowser/Dooble
|
||||
/(flock|rockmelt|midori|epiphany|silk|skyfire|ovibrowser|bolt|iron|vivaldi|iridium|phantomjs|bowser|qupzilla|falkon|rekonq|puffin|brave|whale(?!.+naver)|qqbrowserlite|duckduckgo|klar|helio|(?=comodo_)?dragon|otter|dooble|(?:lg |qute)browser)\/([-\w\.]+)/i,
|
||||
// Rekonq/Puffin/Brave/Whale/QQBrowserLite/QQ//Vivaldi/DuckDuckGo/Klar/Helio/Dragon
|
||||
/(heytap|ovi|115|surf)browser\/([\d\.]+)/i, // HeyTap/Ovi/115/Surf
|
||||
/(ecosia|weibo)(?:__| \w+@)([\d\.]+)/i // Ecosia/Weibo
|
||||
], [NAME, VERSION], [
|
||||
/quark(?:pc)?\/([-\w\.]+)/i // Quark
|
||||
@@ -434,7 +435,7 @@
|
||||
/(tesla)(?: qtcarbrowser|\/(20\d\d\.[-\w\.]+))/i, // Tesla
|
||||
/m?(qqbrowser|2345(?=browser|chrome|explorer))\w*[\/ ]?v?([\w\.]+)/i // QQ/2345
|
||||
], [NAME, VERSION], [
|
||||
/(lbbrowser|rekonq|steam(?= (clie|tenf|gameo)))/i // LieBao Browser/Rekonq/Steam
|
||||
/(lbbrowser|rekonq)/i // LieBao Browser/Rekonq
|
||||
], [NAME], [
|
||||
/ome\/([\w\.]+) \w* ?(iron) saf/i, // Iron
|
||||
/ome\/([\w\.]+).+qihu (360)[es]e/i // 360
|
||||
@@ -450,7 +451,6 @@
|
||||
/\b(line)\/([\w\.]+)\/iab/i, // Line App for Android
|
||||
/(alipay)client\/([\w\.]+)/i, // Alipay
|
||||
/(twitter)(?:and| f.+e\/([\w\.]+))/i, // Twitter
|
||||
/(bing)(?:web|sapphire)\/([\w\.]+)/i, // Bing
|
||||
/(instagram|snapchat|klarna)[\/ ]([-\w\.]+)/i // Instagram/Snapchat/Klarna
|
||||
], [NAME, VERSION, [TYPE, INAPP]], [
|
||||
/\bgsa\/([\w\.]+) .*safari\//i // Google Search Appliance on iOS
|
||||
@@ -508,10 +508,10 @@
|
||||
/(swiftfox)/i, // Swiftfox
|
||||
/(icedragon|iceweasel|camino|chimera|fennec|maemo browser|minimo|conkeror)[\/ ]?([\w\.\+]+)/i,
|
||||
// IceDragon/Iceweasel/Camino/Chimera/Fennec/Maemo/Minimo/Conkeror
|
||||
/(seamonkey|k-meleon|icecat|iceape|firebird|phoenix|basilisk|waterfox)\/([-\w\.]+)$/i,
|
||||
/(seamonkey|k-meleon|icecat|iceape|firebird|phoenix|palemoon|basilisk|waterfox)\/([-\w\.]+)$/i,
|
||||
// Firefox/SeaMonkey/K-Meleon/IceCat/IceApe/Firebird/Phoenix
|
||||
/(firefox)\/([\w\.]+)/i, // Other Firefox-based
|
||||
/(mozilla)\/([\w\.]+(?= .+rv\:.+gecko\/\d+)|[0-4][\w\.]+(?!.+compatible))/i, // Mozilla
|
||||
/(mozilla)\/([\w\.]+) .+rv\:.+gecko\/\d+/i, // Mozilla
|
||||
|
||||
// Other
|
||||
/(amaya|dillo|doris|icab|ladybird|lynx|mosaic|netsurf|obigo|polaris|w3m|(?:go|ice|up)[\. ]?browser)[-\/ ]?v?([\w\.]+)/i,
|
||||
@@ -549,8 +549,6 @@
|
||||
/((ppc|powerpc)(64)?)( mac|;|\))/i, // PowerPC
|
||||
/(?:osf1|[freopnt]{3,4}bsd) (alpha)/i // Alpha
|
||||
], [[ARCHITECTURE, /ower/, EMPTY, lowerize]], [
|
||||
/mc680.0/i
|
||||
], [[ARCHITECTURE, '68k']], [
|
||||
/winnt.+\[axp/i
|
||||
], [[ARCHITECTURE, 'alpha']]
|
||||
],
|
||||
@@ -570,10 +568,11 @@
|
||||
], [MODEL, [VENDOR, SAMSUNG], [TYPE, MOBILE]], [
|
||||
|
||||
// Apple
|
||||
/(?:\/|\()(ip(?:hone|od)[\w, ]*)[\/\);]/i // iPod/iPhone
|
||||
/(?:\/|\()(ip(?:hone|od)[\w, ]*)(?:\/|;)/i // iPod/iPhone
|
||||
], [MODEL, [VENDOR, APPLE], [TYPE, MOBILE]], [
|
||||
/\b(?:ios|apple\w+)\/.+[\(\/](ipad)/i, // iPad
|
||||
/\b(ipad)[\d,]*[;\] ].+(mac |i(pad)?)os/i
|
||||
/\((ipad);[-\w\),; ]+apple/i, // iPad
|
||||
/applecoremedia\/[\w\.]+ \((ipad)/i,
|
||||
/\b(ipad)\d\d?,\d\d?[;\]].+ios/i
|
||||
], [MODEL, [VENDOR, APPLE], [TYPE, TABLET]], [
|
||||
/(macintosh);/i
|
||||
], [MODEL, [VENDOR, APPLE]], [
|
||||
@@ -591,21 +590,21 @@
|
||||
// Huawei
|
||||
/\b((?:ag[rs][2356]?k?|bah[234]?|bg[2o]|bt[kv]|cmr|cpn|db[ry]2?|jdn2|got|kob2?k?|mon|pce|scm|sht?|[tw]gr|vrd)-[ad]?[lw][0125][09]b?|605hw|bg2-u03|(?:gem|fdr|m2|ple|t1)-[7a]0[1-4][lu]|t1-a2[13][lw]|mediapad[\w\. ]*(?= bui|\)))\b(?!.+d\/s)/i
|
||||
], [MODEL, [VENDOR, HUAWEI], [TYPE, TABLET]], [
|
||||
/(?:huawei) ?([-\w ]+)[;\)]/i,
|
||||
/\b(nexus 6p|\w{2,4}e?-[atu]?[ln][\dx][\dc][adnt]?)\b(?!.+d\/s)/i
|
||||
/(?:huawei)([-\w ]+)[;\)]/i,
|
||||
/\b(nexus 6p|\w{2,4}e?-[atu]?[ln][\dx][012359c][adn]?)\b(?!.+d\/s)/i
|
||||
], [MODEL, [VENDOR, HUAWEI], [TYPE, MOBILE]], [
|
||||
|
||||
// Xiaomi
|
||||
/oid[^\)]+; (2[\dbc]{4}(182|283|rp\w{2})[cgl]|m2105k81a?c)(?: bui|\))/i,
|
||||
/\b(?:xiao)?((?:red)?mi[-_ ]?pad[\w- ]*)(?: bui|\))/i // Mi Pad tablets
|
||||
/\b((?:red)?mi[-_ ]?pad[\w- ]*)(?: bui|\))/i // Mi Pad tablets
|
||||
],[[MODEL, /_/g, ' '], [VENDOR, XIAOMI], [TYPE, TABLET]], [
|
||||
|
||||
/\b(poco[\w ]+|m2\d{3}j\d\d[a-z]{2})(?: bui|\))/i, // Xiaomi POCO
|
||||
/\b; (\w+) build\/hm\1/i, // Xiaomi Hongmi 'numeric' models
|
||||
/\b(hm[-_ ]?note?[_ ]?(?:\d\w)?) bui/i, // Xiaomi Hongmi
|
||||
// Xiaomi Redmi / POCO / Black Shark / Qin
|
||||
/oid[^\)]+; (redmi[\-_ ]?(?:note|k)?[\w_ ]+|m?[12]\d[01]\d\w{3,6}|poco[\w ]+|(shark )?\w{3}-[ah]0|qin ?[1-3](s\+|ultra| pro)?)( bui|; wv|\))/i,
|
||||
// Xiaomi Mi
|
||||
/\b(mi[-_ ]?(?:a\d|one|one[_ ]plus|note|max|cc)?[_ ]?(?:\d{0,2}\w?)[_ ]?(?:plus|se|lite|pro)?( 5g|lte)?)(?: bui|\))/i,
|
||||
/\b(redmi[\-_ ]?(?:note|k)?[\w_ ]+)(?: bui|\))/i, // Xiaomi Redmi
|
||||
/oid[^\)]+; (m?[12][0-389][01]\w{3,6}[c-y])( bui|; wv|\))/i, // Xiaomi Redmi 'numeric' models
|
||||
/\b(mi[-_ ]?(?:a\d|one|one[_ ]plus|note lte|max|cc)?[_ ]?(?:\d?\w?)[_ ]?(?:plus|se|lite|pro)?)(?: bui|\))/i, // Xiaomi Mi
|
||||
/ ([\w ]+) miui\/v?\d/i
|
||||
], [[MODEL, /_/g, ' '], [VENDOR, XIAOMI], [TYPE, MOBILE]], [
|
||||
|
||||
@@ -661,7 +660,7 @@
|
||||
/(nokia) (t[12][01])/i
|
||||
], [VENDOR, MODEL, [TYPE, TABLET]], [
|
||||
/(?:maemo|nokia).*(n900|lumia \d+|rm-\d+)/i,
|
||||
/nokia[-_ ]?(([-\w\. ]*?))( bui|\)|;|\/)/i
|
||||
/nokia[-_ ]?(([-\w\. ]*))/i
|
||||
], [[MODEL, /_/g, ' '], [TYPE, MOBILE], [VENDOR, 'Nokia']], [
|
||||
|
||||
// Google
|
||||
@@ -692,7 +691,7 @@
|
||||
/(playbook);[-\w\),; ]+(rim)/i // BlackBerry PlayBook
|
||||
], [MODEL, VENDOR, [TYPE, TABLET]], [
|
||||
/\b((?:bb[a-f]|st[hv])100-\d)/i,
|
||||
/(?:blackberry|\(bb10;) (\w+)/i
|
||||
/\(bb10; (\w+)/i // BlackBerry 10
|
||||
], [MODEL, [VENDOR, BLACKBERRY], [TYPE, MOBILE]], [
|
||||
|
||||
// Asus
|
||||
@@ -772,12 +771,10 @@
|
||||
|
||||
/(blackberry|benq|palm(?=\-)|sonyericsson|acer|asus(?! zenw)|dell|jolla|meizu|motorola|polytron|tecno|micromax|advan)[-_ ]?([-\w]*)/i,
|
||||
// BlackBerry/BenQ/Palm/Sony-Ericsson/Acer/Asus/Dell/Meizu/Motorola/Polytron/Tecno/Micromax/Advan
|
||||
// BLU/HMD/IMO/Infinix/Lava/OnePlus/TCL/Wiko
|
||||
/; (blu|hmd|imo|infinix|lava|oneplus|tcl|wiko)[_ ]([\w\+ ]+?)(?: bui|\)|; r)/i,
|
||||
/; (blu|hmd|imo|infinix|lava|oneplus|tcl)[_ ]([\w\+ ]+?)(?: bui|\)|; r)/i, // BLU/HMD/IMO/Infinix/Lava/OnePlus/TCL
|
||||
/(hp) ([\w ]+\w)/i, // HP iPAQ
|
||||
/(microsoft); (lumia[\w ]+)/i, // Microsoft Lumia
|
||||
/(oppo) ?([\w ]+) bui/i, // OPPO
|
||||
/(hisense) ([ehv][\w ]+)\)/i, // Hisense
|
||||
/droid[^;]+; (philips)[_ ]([sv-x][\d]{3,4}[xz]?)/i // Philips
|
||||
], [VENDOR, MODEL, [TYPE, MOBILE]], [
|
||||
|
||||
@@ -854,10 +851,10 @@
|
||||
], [MODEL, [VENDOR, MICROSOFT], [TYPE, CONSOLE]], [
|
||||
/(ouya)/i, // Ouya
|
||||
/(nintendo) (\w+)/i, // Nintendo
|
||||
/(retroid) (pocket ([^\)]+))/i, // Retroid Pocket
|
||||
/(valve).+(steam deck)/i,
|
||||
/droid.+; ((shield|rgcube|gr0006))( bui|\))/i // Nvidia Portable/Anbernic/Logitech
|
||||
], [[VENDOR, strMapper, { 'Nvidia': 'Shield', 'Anbernic': 'RGCUBE', 'Logitech': 'GR0006' }], MODEL, [TYPE, CONSOLE]], [
|
||||
/(retroid) (pocket ([^\)]+))/i // Retroid Pocket
|
||||
], [VENDOR, MODEL, [TYPE, CONSOLE]], [
|
||||
/droid.+; (shield)( bui|\))/i // Nvidia Portable
|
||||
], [MODEL, [VENDOR, NVIDIA], [TYPE, CONSOLE]], [
|
||||
|
||||
///////////////////
|
||||
// WEARABLES
|
||||
@@ -866,7 +863,7 @@
|
||||
/\b(sm-[lr]\d\d[0156][fnuw]?s?|gear live)\b/i // Samsung Galaxy Watch
|
||||
], [MODEL, [VENDOR, SAMSUNG], [TYPE, WEARABLE]], [
|
||||
/((pebble))app/i, // Pebble
|
||||
/(asus|google|lg|oppo|xiaomi) ((pixel |zen)?watch[\w ]*)( bui|\))/i // Asus ZenWatch / LG Watch / Pixel Watch / Xiaomi Watch
|
||||
/(asus|google|lg|oppo) ((pixel |zen)?watch[\w ]*)( bui|\))/i // Asus ZenWatch / LG Watch / Pixel Watch
|
||||
], [VENDOR, MODEL, [TYPE, WEARABLE]], [
|
||||
/(ow(?:19|20)?we?[1-3]{1,3})/i // Oppo Watch
|
||||
], [MODEL, [VENDOR, OPPO], [TYPE, WEARABLE]], [
|
||||
@@ -917,7 +914,7 @@
|
||||
], [MODEL, [TYPE, SMARTTV]], [
|
||||
/\b((4k|android|smart|opera)[- ]?tv|tv; rv:|large screen[\w ]+safari)\b/i
|
||||
], [[TYPE, SMARTTV]], [
|
||||
/droid .+?; ([^;]+?)(?: bui|; wv\)|\) applew|; hmsc).+?(mobile|vr|\d) safari/i
|
||||
/droid .+?; ([^;]+?)(?: bui|; wv\)|\) applew).+?(mobile|vr|\d) safari/i
|
||||
], [MODEL, [TYPE, strMapper, { 'mobile' : 'Mobile', 'xr' : 'VR', '*' : TABLET }]], [
|
||||
/\b((tablet|tab)[;\/]|focus\/\d(?!.+mobile))/i // Unidentifiable Tablet
|
||||
], [[TYPE, TABLET]], [
|
||||
@@ -970,8 +967,7 @@
|
||||
|
||||
// iOS/macOS
|
||||
/[adehimnop]{4,7}\b(?:.*os ([\w]+) like mac|; opera)/i, // iOS
|
||||
/(?:ios;fbsv|ios(?=.+ip(?:ad|hone)|.+apple ?tv)|ip(?:ad|hone)(?: |.+i(?:pad)?)os|apple ?tv.+ios)[\/ ]([\w\.]+)/i,
|
||||
/\btvos ?([\w\.]+)/i,
|
||||
/(?:ios;fbsv\/|iphone.+ios[\/ ])([\d\.]+)/i,
|
||||
/cfnetwork\/.+darwin/i
|
||||
], [[VERSION, /_/g, '.'], [NAME, 'iOS']], [
|
||||
/(mac os x) ?([\w\. ]*)/i,
|
||||
@@ -1056,27 +1052,27 @@
|
||||
var defaultProps = (function () {
|
||||
var props = { init : {}, isIgnore : {}, isIgnoreRgx : {}, toString : {}};
|
||||
setProps.call(props.init, [
|
||||
[BROWSER, [NAME, VERSION, MAJOR, TYPE]],
|
||||
[CPU, [ARCHITECTURE]],
|
||||
[DEVICE, [TYPE, MODEL, VENDOR]],
|
||||
[ENGINE, [NAME, VERSION]],
|
||||
[OS, [NAME, VERSION]]
|
||||
[UA_BROWSER, [NAME, VERSION, MAJOR, TYPE]],
|
||||
[UA_CPU, [ARCHITECTURE]],
|
||||
[UA_DEVICE, [TYPE, MODEL, VENDOR]],
|
||||
[UA_ENGINE, [NAME, VERSION]],
|
||||
[UA_OS, [NAME, VERSION]]
|
||||
]);
|
||||
setProps.call(props.isIgnore, [
|
||||
[BROWSER, [VERSION, MAJOR]],
|
||||
[ENGINE, [VERSION]],
|
||||
[OS, [VERSION]]
|
||||
[UA_BROWSER, [VERSION, MAJOR]],
|
||||
[UA_ENGINE, [VERSION]],
|
||||
[UA_OS, [VERSION]]
|
||||
]);
|
||||
setProps.call(props.isIgnoreRgx, [
|
||||
[BROWSER, / ?browser$/i],
|
||||
[OS, / ?os$/i]
|
||||
[UA_BROWSER, / ?browser$/i],
|
||||
[UA_OS, / ?os$/i]
|
||||
]);
|
||||
setProps.call(props.toString, [
|
||||
[BROWSER, [NAME, VERSION]],
|
||||
[CPU, [ARCHITECTURE]],
|
||||
[DEVICE, [VENDOR, MODEL]],
|
||||
[ENGINE, [NAME, VERSION]],
|
||||
[OS, [NAME, VERSION]]
|
||||
[UA_BROWSER, [NAME, VERSION]],
|
||||
[UA_CPU, [ARCHITECTURE]],
|
||||
[UA_DEVICE, [VENDOR, MODEL]],
|
||||
[UA_ENGINE, [NAME, VERSION]],
|
||||
[UA_OS, [NAME, VERSION]]
|
||||
]);
|
||||
return props;
|
||||
})();
|
||||
@@ -1120,14 +1116,14 @@
|
||||
return item.detectFeature().get();
|
||||
};
|
||||
|
||||
if (itemType != RESULT) {
|
||||
if (itemType != UA_RESULT) {
|
||||
IData.prototype.is = function (strToCheck) {
|
||||
var is = false;
|
||||
for (var i in this) {
|
||||
if (this.hasOwnProperty(i) && !has(is_ignoreProps, i) && lowerize(is_ignoreRgx ? strip(is_ignoreRgx, this[i]) : this[i]) == lowerize(is_ignoreRgx ? strip(is_ignoreRgx, strToCheck) : strToCheck)) {
|
||||
is = true;
|
||||
if (strToCheck != TYPEOF.UNDEFINED) break;
|
||||
} else if (strToCheck == TYPEOF.UNDEFINED && is) {
|
||||
if (strToCheck != UNDEF_TYPE) break;
|
||||
} else if (strToCheck == UNDEF_TYPE && is) {
|
||||
is = !is;
|
||||
break;
|
||||
}
|
||||
@@ -1137,14 +1133,15 @@
|
||||
IData.prototype.toString = function () {
|
||||
var str = EMPTY;
|
||||
for (var i in toString_props) {
|
||||
if (typeof(this[toString_props[i]]) !== TYPEOF.UNDEFINED) {
|
||||
if (typeof(this[toString_props[i]]) !== UNDEF_TYPE) {
|
||||
str += (str ? ' ' : EMPTY) + this[toString_props[i]];
|
||||
}
|
||||
}
|
||||
return str || TYPEOF.UNDEFINED;
|
||||
return str || UNDEF_TYPE;
|
||||
};
|
||||
}
|
||||
|
||||
if (!NAVIGATOR_UADATA) {
|
||||
IData.prototype.then = function (cb) {
|
||||
var that = this;
|
||||
var IDataResolve = function () {
|
||||
@@ -1156,14 +1153,13 @@
|
||||
};
|
||||
IDataResolve.prototype = {
|
||||
is : IData.prototype.is,
|
||||
toString : IData.prototype.toString,
|
||||
withClientHints : IData.prototype.withClientHints,
|
||||
withFeatureCheck : IData.prototype.withFeatureCheck
|
||||
toString : IData.prototype.toString
|
||||
};
|
||||
var resolveData = new IDataResolve();
|
||||
cb(resolveData);
|
||||
return resolveData;
|
||||
};
|
||||
}
|
||||
|
||||
return new IData();
|
||||
};
|
||||
@@ -1177,76 +1173,67 @@
|
||||
setProps.call(this, CH_ALL_VALUES);
|
||||
if (isHttpUACH) {
|
||||
setProps.call(this, [
|
||||
[BRANDS, itemListToArray(uach[CH])],
|
||||
[FULLVERLIST, itemListToArray(uach[CH_FULL_VER_LIST])],
|
||||
[MOBILE, /\?1/.test(uach[CH_MOBILE])],
|
||||
[MODEL, stripQuotes(uach[CH_MODEL])],
|
||||
[PLATFORM, stripQuotes(uach[CH_PLATFORM])],
|
||||
[PLATFORMVER, stripQuotes(uach[CH_PLATFORM_VER])],
|
||||
[ARCHITECTURE, stripQuotes(uach[CH_ARCH])],
|
||||
[FORMFACTORS, itemListToArray(uach[CH_FORM_FACTORS])],
|
||||
[BITNESS, stripQuotes(uach[CH_BITNESS])]
|
||||
[BRANDS, itemListToArray(uach[CH_HEADER])],
|
||||
[FULLVERLIST, itemListToArray(uach[CH_HEADER_FULL_VER_LIST])],
|
||||
[MOBILE, /\?1/.test(uach[CH_HEADER_MOBILE])],
|
||||
[MODEL, stripQuotes(uach[CH_HEADER_MODEL])],
|
||||
[PLATFORM, stripQuotes(uach[CH_HEADER_PLATFORM])],
|
||||
[PLATFORMVER, stripQuotes(uach[CH_HEADER_PLATFORM_VER])],
|
||||
[ARCHITECTURE, stripQuotes(uach[CH_HEADER_ARCH])],
|
||||
[FORMFACTORS, itemListToArray(uach[CH_HEADER_FORM_FACTORS])],
|
||||
[BITNESS, stripQuotes(uach[CH_HEADER_BITNESS])]
|
||||
]);
|
||||
} else {
|
||||
for (var prop in uach) {
|
||||
if(this.hasOwnProperty(prop) && typeof uach[prop] !== TYPEOF.UNDEFINED) this[prop] = uach[prop];
|
||||
if(this.hasOwnProperty(prop) && typeof uach[prop] !== UNDEF_TYPE) this[prop] = uach[prop];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function UAItem (itemType, ua, rgxMap, uaCH) {
|
||||
setProps.call(this, [
|
||||
['itemType', itemType],
|
||||
['ua', ua],
|
||||
['uaCH', uaCH],
|
||||
['rgxMap', rgxMap],
|
||||
['data', createIData(this, itemType)]
|
||||
]);
|
||||
return this;
|
||||
}
|
||||
|
||||
UAItem.prototype.get = function (prop) {
|
||||
this.get = function (prop) {
|
||||
if (!prop) return this.data;
|
||||
return this.data.hasOwnProperty(prop) ? this.data[prop] : undefined;
|
||||
};
|
||||
|
||||
UAItem.prototype.set = function (prop, val) {
|
||||
this.set = function (prop, val) {
|
||||
this.data[prop] = val;
|
||||
return this;
|
||||
};
|
||||
|
||||
UAItem.prototype.setCH = function (ch) {
|
||||
this.setCH = function (ch) {
|
||||
this.uaCH = ch;
|
||||
return this;
|
||||
};
|
||||
|
||||
UAItem.prototype.detectFeature = function () {
|
||||
this.detectFeature = function () {
|
||||
if (NAVIGATOR && NAVIGATOR.userAgent == this.ua) {
|
||||
switch (this.itemType) {
|
||||
case BROWSER:
|
||||
case UA_BROWSER:
|
||||
// Brave-specific detection
|
||||
if (NAVIGATOR.brave && typeof NAVIGATOR.brave.isBrave == TYPEOF.FUNCTION) {
|
||||
if (NAVIGATOR.brave && typeof NAVIGATOR.brave.isBrave == FUNC_TYPE) {
|
||||
this.set(NAME, 'Brave');
|
||||
}
|
||||
break;
|
||||
case DEVICE:
|
||||
case UA_DEVICE:
|
||||
// Chrome-specific detection: check for 'mobile' value of navigator.userAgentData
|
||||
if (!this.get(TYPE) && NAVIGATOR_UADATA && NAVIGATOR_UADATA[MOBILE]) {
|
||||
this.set(TYPE, MOBILE);
|
||||
}
|
||||
// iPadOS-specific detection: identified as Mac, but has some iOS-only properties
|
||||
if (this.get(MODEL) == 'Macintosh' && NAVIGATOR && typeof NAVIGATOR.standalone !== TYPEOF.UNDEFINED && NAVIGATOR.maxTouchPoints && NAVIGATOR.maxTouchPoints > 2) {
|
||||
if (this.get(MODEL) == 'Macintosh' && NAVIGATOR && typeof NAVIGATOR.standalone !== UNDEF_TYPE && NAVIGATOR.maxTouchPoints && NAVIGATOR.maxTouchPoints > 2) {
|
||||
this.set(MODEL, 'iPad')
|
||||
.set(TYPE, TABLET);
|
||||
}
|
||||
break;
|
||||
case OS:
|
||||
case UA_OS:
|
||||
// Chrome-specific detection: check for 'platform' value of navigator.userAgentData
|
||||
if (!this.get(NAME) && NAVIGATOR_UADATA && NAVIGATOR_UADATA[PLATFORM]) {
|
||||
this.set(NAME, NAVIGATOR_UADATA[PLATFORM]);
|
||||
}
|
||||
break;
|
||||
case RESULT:
|
||||
case UA_RESULT:
|
||||
var data = this.data;
|
||||
var detect = function (itemType) {
|
||||
return data[itemType]
|
||||
@@ -1254,50 +1241,39 @@
|
||||
.detectFeature()
|
||||
.get();
|
||||
};
|
||||
this.set(BROWSER, detect(BROWSER))
|
||||
.set(CPU, detect(CPU))
|
||||
.set(DEVICE, detect(DEVICE))
|
||||
.set(ENGINE, detect(ENGINE))
|
||||
.set(OS, detect(OS));
|
||||
this.set(UA_BROWSER, detect(UA_BROWSER))
|
||||
.set(UA_CPU, detect(UA_CPU))
|
||||
.set(UA_DEVICE, detect(UA_DEVICE))
|
||||
.set(UA_ENGINE, detect(UA_ENGINE))
|
||||
.set(UA_OS, detect(UA_OS));
|
||||
}
|
||||
}
|
||||
return this;
|
||||
};
|
||||
|
||||
UAItem.prototype.parseUA = function () {
|
||||
if (this.itemType != RESULT) {
|
||||
this.parseUA = function () {
|
||||
if (this.itemType != UA_RESULT) {
|
||||
rgxMapper.call(this.data, this.ua, this.rgxMap);
|
||||
}
|
||||
switch (this.itemType) {
|
||||
case BROWSER:
|
||||
if (this.itemType == UA_BROWSER) {
|
||||
this.set(MAJOR, majorize(this.get(VERSION)));
|
||||
break;
|
||||
case OS:
|
||||
if (this.get(NAME) == 'iOS' && this.get(VERSION) == '18.6') {
|
||||
// Based on the assumption that iOS version is tightly coupled with Safari version
|
||||
var realVersion = /\) Version\/([\d\.]+)/.exec(this.ua); // Get Safari version
|
||||
if (realVersion && parseInt(realVersion[1].substring(0,2), 10) >= 26) {
|
||||
this.set(VERSION, realVersion[1]); // Set as iOS version
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
return this;
|
||||
};
|
||||
|
||||
UAItem.prototype.parseCH = function () {
|
||||
this.parseCH = function () {
|
||||
var uaCH = this.uaCH,
|
||||
rgxMap = this.rgxMap;
|
||||
|
||||
switch (this.itemType) {
|
||||
case BROWSER:
|
||||
case ENGINE:
|
||||
case UA_BROWSER:
|
||||
case UA_ENGINE:
|
||||
var brands = uaCH[FULLVERLIST] || uaCH[BRANDS], prevName;
|
||||
if (brands) {
|
||||
for (var i=0; i<brands.length; i++) {
|
||||
var brandName = brands[i].brand || brands[i],
|
||||
brandVersion = brands[i].version;
|
||||
if (this.itemType == BROWSER &&
|
||||
if (this.itemType == UA_BROWSER &&
|
||||
!/not.a.brand/i.test(brandName) &&
|
||||
(!prevName ||
|
||||
(/Chrom/.test(prevName) && brandName != CHROMIUM) ||
|
||||
@@ -1312,20 +1288,20 @@
|
||||
}
|
||||
prevName = brandName;
|
||||
}
|
||||
if (this.itemType == ENGINE && brandName == CHROMIUM) {
|
||||
if (this.itemType == UA_ENGINE && brandName == CHROMIUM) {
|
||||
this.set(VERSION, brandVersion);
|
||||
}
|
||||
}
|
||||
}
|
||||
break;
|
||||
case CPU:
|
||||
case UA_CPU:
|
||||
var archName = uaCH[ARCHITECTURE];
|
||||
if (archName) {
|
||||
if (archName && uaCH[BITNESS] == '64') archName += '64';
|
||||
rgxMapper.call(this.data, archName + ';', rgxMap);
|
||||
}
|
||||
break;
|
||||
case DEVICE:
|
||||
case UA_DEVICE:
|
||||
if (uaCH[MOBILE]) {
|
||||
this.set(TYPE, MOBILE);
|
||||
}
|
||||
@@ -1355,7 +1331,7 @@
|
||||
this.set(TYPE, ff);
|
||||
}
|
||||
break;
|
||||
case OS:
|
||||
case UA_OS:
|
||||
var osName = uaCH[PLATFORM];
|
||||
if(osName) {
|
||||
var osVersion = uaCH[PLATFORMVER];
|
||||
@@ -1369,7 +1345,7 @@
|
||||
.set(VERSION, undefined);
|
||||
}
|
||||
break;
|
||||
case RESULT:
|
||||
case UA_RESULT:
|
||||
var data = this.data;
|
||||
var parse = function (itemType) {
|
||||
return data[itemType]
|
||||
@@ -1378,20 +1354,31 @@
|
||||
.parseCH()
|
||||
.get();
|
||||
};
|
||||
this.set(BROWSER, parse(BROWSER))
|
||||
.set(CPU, parse(CPU))
|
||||
.set(DEVICE, parse(DEVICE))
|
||||
.set(ENGINE, parse(ENGINE))
|
||||
.set(OS, parse(OS));
|
||||
this.set(UA_BROWSER, parse(UA_BROWSER))
|
||||
.set(UA_CPU, parse(UA_CPU))
|
||||
.set(UA_DEVICE, parse(UA_DEVICE))
|
||||
.set(UA_ENGINE, parse(UA_ENGINE))
|
||||
.set(UA_OS, parse(UA_OS));
|
||||
}
|
||||
return this;
|
||||
};
|
||||
|
||||
setProps.call(this, [
|
||||
['itemType', itemType],
|
||||
['ua', ua],
|
||||
['uaCH', uaCH],
|
||||
['rgxMap', rgxMap],
|
||||
['data', createIData(this, itemType)]
|
||||
]);
|
||||
|
||||
return this;
|
||||
}
|
||||
|
||||
function UAParser (ua, extensions, headers) {
|
||||
|
||||
if (typeof ua === TYPEOF.OBJECT) {
|
||||
if (typeof ua === OBJ_TYPE) {
|
||||
if (isExtensions(ua, true)) {
|
||||
if (typeof extensions === TYPEOF.OBJECT) {
|
||||
if (typeof extensions === OBJ_TYPE) {
|
||||
headers = extensions; // case UAParser(extensions, headers)
|
||||
}
|
||||
extensions = ua; // case UAParser(extensions)
|
||||
@@ -1400,13 +1387,13 @@
|
||||
extensions = undefined;
|
||||
}
|
||||
ua = undefined;
|
||||
} else if (typeof ua === TYPEOF.STRING && !isExtensions(extensions, true)) {
|
||||
} else if (typeof ua === STR_TYPE && !isExtensions(extensions, true)) {
|
||||
headers = extensions; // case UAParser(ua, headers)
|
||||
extensions = undefined;
|
||||
}
|
||||
|
||||
if (headers) {
|
||||
if (typeof headers.append === TYPEOF.FUNCTION) {
|
||||
if (typeof headers.append === FUNC_TYPE) {
|
||||
// Convert Headers object into a plain object
|
||||
var kv = {};
|
||||
headers.forEach(function (v, k) { kv[String(k).toLowerCase()] = v; });
|
||||
@@ -1427,7 +1414,7 @@
|
||||
return new UAParser(ua, extensions, headers).getResult();
|
||||
}
|
||||
|
||||
var userAgent = typeof ua === TYPEOF.STRING ? ua : // Passed user-agent string
|
||||
var userAgent = typeof ua === STR_TYPE ? ua : // Passed user-agent string
|
||||
(headers && headers[USER_AGENT] ? headers[USER_AGENT] : // User-Agent from passed headers
|
||||
((NAVIGATOR && NAVIGATOR.userAgent) ? NAVIGATOR.userAgent : // navigator.userAgent
|
||||
EMPTY)), // empty string
|
||||
@@ -1438,15 +1425,15 @@
|
||||
defaultRegexes,
|
||||
|
||||
createItemFunc = function (itemType) {
|
||||
if (itemType == RESULT) {
|
||||
if (itemType == UA_RESULT) {
|
||||
return function () {
|
||||
return new UAItem(itemType, userAgent, regexMap, httpUACH)
|
||||
.set('ua', userAgent)
|
||||
.set(BROWSER, this.getBrowser())
|
||||
.set(CPU, this.getCPU())
|
||||
.set(DEVICE, this.getDevice())
|
||||
.set(ENGINE, this.getEngine())
|
||||
.set(OS, this.getOS())
|
||||
.set(UA_BROWSER, this.getBrowser())
|
||||
.set(UA_CPU, this.getCPU())
|
||||
.set(UA_DEVICE, this.getDevice())
|
||||
.set(UA_ENGINE, this.getEngine())
|
||||
.set(UA_OS, this.getOS())
|
||||
.get();
|
||||
};
|
||||
} else {
|
||||
@@ -1460,15 +1447,16 @@
|
||||
|
||||
// public methods
|
||||
setProps.call(this, [
|
||||
['getBrowser', createItemFunc(BROWSER)],
|
||||
['getCPU', createItemFunc(CPU)],
|
||||
['getDevice', createItemFunc(DEVICE)],
|
||||
['getEngine', createItemFunc(ENGINE)],
|
||||
['getOS', createItemFunc(OS)],
|
||||
['getResult', createItemFunc(RESULT)],
|
||||
['getBrowser', createItemFunc(UA_BROWSER)],
|
||||
['getCPU', createItemFunc(UA_CPU)],
|
||||
['getDevice', createItemFunc(UA_DEVICE)],
|
||||
['getEngine', createItemFunc(UA_ENGINE)],
|
||||
['getOS', createItemFunc(UA_OS)],
|
||||
['getResult', createItemFunc(UA_RESULT)],
|
||||
['getUA', function () { return userAgent; }],
|
||||
['setUA', function (ua) {
|
||||
if (isString(ua)) userAgent = trim(ua, UA_MAX_LENGTH);
|
||||
if (isString(ua))
|
||||
userAgent = ua.length > UA_MAX_LENGTH ? trim(ua, UA_MAX_LENGTH) : ua;
|
||||
return this;
|
||||
}]
|
||||
])
|
||||
|
||||
@@ -171,16 +171,6 @@
|
||||
"major" : "0"
|
||||
}
|
||||
},
|
||||
{
|
||||
"desc" : "Atlas",
|
||||
"ua" : "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/141.0.0.0 Safari/537.36 Atlas/1.0",
|
||||
"expect" :
|
||||
{
|
||||
"name" : "Atlas",
|
||||
"version" : "1.0",
|
||||
"major" : "1"
|
||||
}
|
||||
},
|
||||
{
|
||||
"desc" : "Avant",
|
||||
"ua" : "Mozilla/4.0 (compatible; MSIE 8.0; Windows NT 5.1; Trident/4.0; GTB5; Avant Browser; .NET CLR 1.1.4322; .NET CLR 2.0.50727)",
|
||||
@@ -281,26 +271,6 @@
|
||||
"major" : "11"
|
||||
}
|
||||
},
|
||||
{
|
||||
"desc" : "Bing",
|
||||
"ua" : "Mozilla/5.0 (iPhone; CPU iPhone OS 18_5 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/18.5 Mobile/15E148 Safari/605.1.15 BingSapphire/31.8.430522001",
|
||||
"expect" :
|
||||
{
|
||||
"name" : "Bing",
|
||||
"version" : "31.8.430522001",
|
||||
"major" : "31"
|
||||
}
|
||||
},
|
||||
{
|
||||
"desc" : "Bing",
|
||||
"ua" : "Mozilla/5.0 (Linux; Android 9; MIX 2 Build/PKQ1.190118.001; wv) AppleWebKit/537.36 (KHTML, like Gecko) Version/4.0 Chrome/100.0.4893.0 Mobile Safari/537.36 BingWeb/6.9.12",
|
||||
"expect" :
|
||||
{
|
||||
"name" : "Bing",
|
||||
"version" : "6.9.12",
|
||||
"major" : "6"
|
||||
}
|
||||
},
|
||||
{
|
||||
"desc" : "Blazer",
|
||||
"ua" : "Mozilla/4.0 (compatible; MSIE 6.0; Windows 98; PalmSource/hspr-H102; Blazer/4.0) 16;320x320",
|
||||
@@ -641,16 +611,6 @@
|
||||
"major" : "55"
|
||||
}
|
||||
},
|
||||
{
|
||||
"desc" : "PaleMoon",
|
||||
"ua" : "(Windows NT 6.2; WOW64) KHTML/4.11 Gecko/20130308 Firefox/23.0 (PaleMoon/20.3)",
|
||||
"expect" :
|
||||
{
|
||||
"name" : "PaleMoon",
|
||||
"version" : "20.3",
|
||||
"major" : "20"
|
||||
}
|
||||
},
|
||||
{
|
||||
"desc" : "PaleMoon",
|
||||
"ua" : "Mozilla/5.0 (X11; Linux x86_64; rv:52.9) Gecko/20100101 Goanna/3.4 Firefox/52.9 PaleMoon/27.6.1",
|
||||
@@ -1378,16 +1338,6 @@
|
||||
"major" : "5"
|
||||
}
|
||||
},
|
||||
{
|
||||
"desc" : "Mozilla",
|
||||
"ua" : "Mozilla/2.02 [fr] (WinNT; I)",
|
||||
"expect" :
|
||||
{
|
||||
"name" : "Mozilla",
|
||||
"version" : "2.02",
|
||||
"major" : "2"
|
||||
}
|
||||
},
|
||||
{
|
||||
"desc" : "MSIE",
|
||||
"ua" : "Mozilla/4.0 (compatible; MSIE 5.0b1; Mac_PowerPC)",
|
||||
@@ -1738,36 +1688,6 @@
|
||||
"major" : "2"
|
||||
}
|
||||
},
|
||||
{
|
||||
"desc" : "Qwant",
|
||||
"ua" : "Mozilla/5.0 (iPhone; CPU iPhone OS 16_1_2 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) QwantMobile/6.7.6 Mobile/15E148 Safari/605.1.15",
|
||||
"expect" :
|
||||
{
|
||||
"name" : "Qwant",
|
||||
"version" : "6.7.6",
|
||||
"major" : "6"
|
||||
}
|
||||
},
|
||||
{
|
||||
"desc" : "Qwant",
|
||||
"ua" : "QwantMobile/2.0 (Android 8.0.0; Mobile; rv:59.0) Gecko/59.0 Firefox/59.0 QwantBrowser/59.0",
|
||||
"expect" :
|
||||
{
|
||||
"name" : "Qwant",
|
||||
"version" : "59.0",
|
||||
"major" : "59"
|
||||
}
|
||||
},
|
||||
{
|
||||
"desc" : "Qwant",
|
||||
"ua" : "QwantMobile/2.0 (iPad; CPU OS 15_8_3 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) QwantiOS/2.7.0b1 Mobile/15E148 Safari/605.1.15",
|
||||
"expect" :
|
||||
{
|
||||
"name" : "Qwant",
|
||||
"version" : "2.0",
|
||||
"major" : "2"
|
||||
}
|
||||
},
|
||||
{
|
||||
"desc" : "Rekonq 2",
|
||||
"ua" : "Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.21 (KHTML, like Gecko) rekonq/2.2.1 Safari/537.21",
|
||||
@@ -1959,36 +1879,6 @@
|
||||
"major" : "20"
|
||||
}
|
||||
},
|
||||
{
|
||||
"desc" : "Steam Client",
|
||||
"ua" : "Mozilla/5.0 (X11; Linux x86_64; Valve Steam Client/default/1705108172) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/85.0.4183.121 Safari/537.36",
|
||||
"expect" :
|
||||
{
|
||||
"name" : "Steam",
|
||||
"version" : "undefined",
|
||||
"major" : "undefined"
|
||||
}
|
||||
},
|
||||
{
|
||||
"desc" : "Steam Big Picture",
|
||||
"ua" : "Mozilla/5.0 (Linux; U; X11; en-US; Valve Steam Tenfoot/1660688177; ) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/84.0.4147.105 Safari/537.36",
|
||||
"expect" :
|
||||
{
|
||||
"name" : "Steam",
|
||||
"version" : "undefined",
|
||||
"major" : "undefined"
|
||||
}
|
||||
},
|
||||
{
|
||||
"desc" : "Steam Overlay",
|
||||
"ua" : "Mozilla/5.0 (Windows NT 10.0; Win64; x64; Valve Steam GameOverlay/default/1741737356) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/126.0.6478.183 Safari/537.36",
|
||||
"expect" :
|
||||
{
|
||||
"name" : "Steam",
|
||||
"version" : "undefined",
|
||||
"major" : "undefined"
|
||||
}
|
||||
},
|
||||
{
|
||||
"desc" : "Swiftfox",
|
||||
"ua" : "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.8.1) Gecko/20061024 Firefox/2.0 (Swiftfox)",
|
||||
|
||||
@@ -289,15 +289,7 @@
|
||||
},
|
||||
{
|
||||
"desc" : "68k",
|
||||
"ua" : "Mozilla/1.1 (Macintosh; U; 68K)",
|
||||
"expect" :
|
||||
{
|
||||
"architecture" : "68k"
|
||||
}
|
||||
},
|
||||
{
|
||||
"desc" : "MC680x0",
|
||||
"ua" : "AmigaVoyager/3.2 (AmigaOS/MC680x0)",
|
||||
"ua" : "'Mozilla/1.1 (Macintosh; U; 68K)'",
|
||||
"expect" :
|
||||
{
|
||||
"architecture" : "68k"
|
||||
|
||||
@@ -1,11 +0,0 @@
|
||||
[
|
||||
{
|
||||
"desc": "Anbernic",
|
||||
"ua": "Mozilla/5.0 (Linux; Android 13; RGCUBE) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/131.0.0.0 Mobile Safari/537.36",
|
||||
"expect": {
|
||||
"vendor": "Anbernic",
|
||||
"model": "RGCUBE",
|
||||
"type": "console"
|
||||
}
|
||||
}
|
||||
]
|
||||
@@ -44,105 +44,6 @@
|
||||
"type": "tablet"
|
||||
}
|
||||
},
|
||||
{
|
||||
"desc": "iPad using Chrome",
|
||||
"ua": "Mozilla/5.0 (iPad13,10; CPU OS 16_6_2 like Mac OS X) AppleWebKit/602.3 (KHTML, like Gecko) CriOS/97.0.0.5927.72 Mobile/11S296 Safari/602.3",
|
||||
"expect": {
|
||||
"vendor": "Apple",
|
||||
"model": "iPad",
|
||||
"type": "tablet"
|
||||
}
|
||||
},
|
||||
{
|
||||
"desc": "iPad using DuckDuckGo",
|
||||
"ua": "Mozilla/5.0 (iPad; iPad13,6 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) DuckDuckGo/130.0.0.0 Mobile/15E148 Safari/604.1",
|
||||
"expect": {
|
||||
"vendor": "Apple",
|
||||
"model": "iPad",
|
||||
"type": "tablet"
|
||||
}
|
||||
},
|
||||
{
|
||||
"desc": "iPad using Discord",
|
||||
"ua": "Discord/52.0 (iPad; iOS 14.4; Scale/2.00)",
|
||||
"expect": {
|
||||
"vendor": "Apple",
|
||||
"model": "iPad",
|
||||
"type": "tablet"
|
||||
}
|
||||
},
|
||||
{
|
||||
"desc": "iPad using Firefox",
|
||||
"ua": "Mozilla/5.0 (iPad; iPad14,2 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) Firefox/120.0 Mobile/15E148 Safari/604.1",
|
||||
"expect": {
|
||||
"vendor": "Apple",
|
||||
"model": "iPad",
|
||||
"type": "tablet"
|
||||
}
|
||||
},
|
||||
{
|
||||
"desc": "iPad using iTunes",
|
||||
"ua": "itunesstored/1.0 iOS/15.6.1 model/iPad13,8 hwp/t8103 build/19G82 (5; dt:238)",
|
||||
"expect": {
|
||||
"vendor": "Apple",
|
||||
"model": "iPad",
|
||||
"type": "tablet"
|
||||
}
|
||||
},
|
||||
{
|
||||
"desc": "iPad using MS OneNote",
|
||||
"ua": "Microsoft Office OneNote/16.81/240108 (iOS/16.5.1; Tablet; AppStore; Apple/iPad8,3)",
|
||||
"expect": {
|
||||
"vendor": "Apple",
|
||||
"model": "iPad",
|
||||
"type": "tablet"
|
||||
}
|
||||
},
|
||||
{
|
||||
"desc": "iPad using MS Word",
|
||||
"ua": "Microsoft Office Word/2.44.1211 (iOS/13.7; Tablet; es-MX; AppStore; Apple/iPad11,3)",
|
||||
"expect": {
|
||||
"vendor": "Apple",
|
||||
"model": "iPad",
|
||||
"type": "tablet"
|
||||
}
|
||||
},
|
||||
{
|
||||
"desc": "iPad using Quora",
|
||||
"ua": "Quora 8.4.30 rv:3230 env:prod (iPad11,3; iPadOS 17.7; en_GB) AppleWebKit",
|
||||
"expect": {
|
||||
"vendor": "Apple",
|
||||
"model": "iPad",
|
||||
"type": "tablet"
|
||||
}
|
||||
},
|
||||
{
|
||||
"desc": "iPad using TuneIn Radio",
|
||||
"ua": "TuneIn Radio/27.1.0; iPad6,3; iPadOS/16.6",
|
||||
"expect": {
|
||||
"vendor": "Apple",
|
||||
"model": "iPad",
|
||||
"type": "tablet"
|
||||
}
|
||||
},
|
||||
{
|
||||
"desc": "iPad using TuneIn Radio Pro",
|
||||
"ua": "TuneIn Radio Pro/21.4.1; iPad8,9; iOS/15.0",
|
||||
"expect": {
|
||||
"vendor": "Apple",
|
||||
"model": "iPad",
|
||||
"type": "tablet"
|
||||
}
|
||||
},
|
||||
{
|
||||
"desc": "iPad using YouTube",
|
||||
"ua": "com.google.ios.youtube/20.31.6 (iPad13,5; U; CPU iPadOS 18_6 like Mac OS X; en_US)",
|
||||
"expect": {
|
||||
"vendor": "Apple",
|
||||
"model": "iPad",
|
||||
"type": "tablet"
|
||||
}
|
||||
},
|
||||
{
|
||||
"desc": "iPod",
|
||||
"ua": "Mozilla/5.0 (iPod touch; CPU iPhone OS 7_0_4 like Mac OS X) AppleWebKit/537.51.1 (KHTML, like Gecko) Version/7.0 Mobile/11B554a Safari/9537.53",
|
||||
@@ -161,15 +62,6 @@
|
||||
"type": "mobile"
|
||||
}
|
||||
},
|
||||
{
|
||||
"desc": "iPhone using Spotify",
|
||||
"ua": "Spotify/8.7.70 iOS/16.0 (iPhone15,3)",
|
||||
"expect": {
|
||||
"vendor": "Apple",
|
||||
"model": "iPhone15,3",
|
||||
"type": "mobile"
|
||||
}
|
||||
},
|
||||
{
|
||||
"desc": "iPhone SE",
|
||||
"ua": "Mozilla/5.0 (iPhone; CPU iPhone OS 13_3_1 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) Mobile/15E148 [FBAN/FBIOS;FBDV/iPhone8,4;FBMD/iPhone;FBSN/iOS;FBSV/13.3.1;FBSS/2;FBID/phone;FBLC/en_US;FBOP/5;FBCR/]",
|
||||
|
||||
@@ -1,25 +1,7 @@
|
||||
[
|
||||
{
|
||||
"desc": "BlackBerry 9650",
|
||||
"ua": "Mozilla/5.0 (BlackBerry; U; BlackBerry 9650; en-US) AppleWebKit/534.8+ (KHTML, like Gecko) Version/6.0.0.524 Mobile Safari/534.8+",
|
||||
"expect": {
|
||||
"vendor": "BlackBerry",
|
||||
"model": "9650",
|
||||
"type": "mobile"
|
||||
}
|
||||
},
|
||||
{
|
||||
"desc": "BlackBerry 9780",
|
||||
"ua": "Mozilla/5.0 (BlackBerry; U; BlackBerry 9780; en) AppleWebKit/534.8+ (KHTML, like Gecko) Version/6.0.0.546 Mobile Safari/534.8+",
|
||||
"expect": {
|
||||
"vendor": "BlackBerry",
|
||||
"model": "9780",
|
||||
"type": "mobile"
|
||||
}
|
||||
},
|
||||
{
|
||||
"desc": "BlackBerry Priv",
|
||||
"ua": "Mozilla/5.0 (Linux; Android 5.1.1; STV100-1 Build/LMY47V; wv) AppleWebKit/537.36 (KHTML, like Gecko) Version/4.0 Chrome/46.0.2490.76 Mobile Safari/537.36",
|
||||
"ua": "User-Agent: Mozilla/5.0 (Linux; Android 5.1.1; STV100-1 Build/LMY47V; wv) AppleWebKit/537.36 (KHTML, like Gecko) Version/4.0 Chrome/46.0.2490.76 Mobile Safari/537.36",
|
||||
"expect": {
|
||||
"vendor": "BlackBerry",
|
||||
"model": "STV100-1",
|
||||
@@ -46,7 +28,7 @@
|
||||
},
|
||||
{
|
||||
"desc": "BlackBerry Key2 LE",
|
||||
"ua": "Mozilla/5.0 (Linux; Android 8.1.0; BBE100-1 Build/OPM1.171019.026) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/69.0.3497 Mobile Safari/537.36",
|
||||
"ua": "User-Agent: Mozilla/5.0 (Linux; Android 8.1.0; BBE100-1 Build/OPM1.171019.026) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/69.0.3497 Mobile Safari/537.36",
|
||||
"expect": {
|
||||
"vendor": "BlackBerry",
|
||||
"model": "BBE100-1",
|
||||
|
||||
@@ -1,20 +0,0 @@
|
||||
[
|
||||
{
|
||||
"desc": "Hisense E50 Lite",
|
||||
"ua": "Mozilla/5.0 (Linux; Android 11; Hisense E50 Lite) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/106.0.5249.126 Mobile Safari/537.36",
|
||||
"expect": {
|
||||
"vendor": "Hisense",
|
||||
"model": "E50 Lite",
|
||||
"type": "mobile"
|
||||
}
|
||||
},
|
||||
{
|
||||
"desc": "Hisense V40s",
|
||||
"ua": "Mozilla/5.0 (Linux; Android 11; Hisense V40s) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/105.0.5195.125 Mobile Safari/537.36",
|
||||
"expect": {
|
||||
"vendor": "Hisense",
|
||||
"model": "V40s",
|
||||
"type": "mobile"
|
||||
}
|
||||
}
|
||||
]
|
||||
@@ -701,15 +701,6 @@
|
||||
"type": "mobile"
|
||||
}
|
||||
},
|
||||
{
|
||||
"desc": "Huawei P10 Lite",
|
||||
"ua": "Mozilla/5.0 (Linux; Android 8.0.0; WAS-L03T) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/107.0.5199.205 Mobile Safari/537.36",
|
||||
"expect": {
|
||||
"vendor": "Huawei",
|
||||
"model": "WAS-L03T",
|
||||
"type": "mobile"
|
||||
}
|
||||
},
|
||||
{
|
||||
"desc": "Huawei P20 Lite",
|
||||
"ua": "Mozilla/5.0 (Linux; Android 8.0.0; ANE-LX1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/75.0.3770.143 Mobile Safari/537.36",
|
||||
@@ -737,15 +728,6 @@
|
||||
"type": "mobile"
|
||||
}
|
||||
},
|
||||
{
|
||||
"desc": "Huawei P30",
|
||||
"ua": "Mozilla/5.0 (Linux; Android 10; ELE-L04) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/91.0.4472.109 Mobile Safari/537.36",
|
||||
"expect": {
|
||||
"vendor": "Huawei",
|
||||
"model": "ELE-L04",
|
||||
"type": "mobile"
|
||||
}
|
||||
},
|
||||
{
|
||||
"desc": "Huawei P30",
|
||||
"ua": "Mozilla/5.0 (Linux; Android 9; ELE-L29) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/73.0.3683.90 Mobile Safari/537.36",
|
||||
@@ -800,15 +782,6 @@
|
||||
"type": "mobile"
|
||||
}
|
||||
},
|
||||
{
|
||||
"desc": "Huawei Nova",
|
||||
"ua": "Mozilla/5.0 (Linux; Android 7.0; HUAWEI CAN-L13) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/106.0.5113.212 Mobile Safari/537.36",
|
||||
"expect": {
|
||||
"vendor": "Huawei",
|
||||
"model": "CAN-L13",
|
||||
"type": "mobile"
|
||||
}
|
||||
},
|
||||
{
|
||||
"desc": "Huawei Nova 5T",
|
||||
"ua": "Mozilla/5.0 (Linux; Android 10; YAL-L21) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/80.0.3987.132 Mobile Safari/537.36",
|
||||
@@ -926,15 +899,6 @@
|
||||
"type": "mobile"
|
||||
}
|
||||
},
|
||||
{
|
||||
"desc": "Huawei Y7p",
|
||||
"ua": "Mozilla/5.0 (Linux; Android 10; ART-L28; HMSCore 6.8.0.311) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/92.0.4476.0 HuaweiBrowser/12.1.2.312 Mobile Safari/537.36",
|
||||
"expect": {
|
||||
"vendor": "Huawei",
|
||||
"model": "ART-L28",
|
||||
"type": "mobile"
|
||||
}
|
||||
},
|
||||
{
|
||||
"desc": "Huawei Y7p",
|
||||
"ua": "Mozilla/5.0 (Linux; Android 9; ART-L29) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/77.0.3865.92 Mobile Safari/537.36",
|
||||
|
||||
@@ -1,11 +0,0 @@
|
||||
[
|
||||
{
|
||||
"desc": "Logitech",
|
||||
"ua": "Dalvik/2.1.0 (Linux; U; Android 11; GR0006 Build/SQ02K.00.0018)",
|
||||
"expect": {
|
||||
"vendor": "Logitech",
|
||||
"model": "GR0006",
|
||||
"type": "console"
|
||||
}
|
||||
}
|
||||
]
|
||||
@@ -1,13 +1,4 @@
|
||||
[
|
||||
{
|
||||
"desc": "Nokia 1",
|
||||
"ua": "Mozilla/5.0 (Linux; Android 10; Nokia 1 Build/QP1A.190711.020) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/107.0.5304.15 Mobile Safari/537.36",
|
||||
"expect": {
|
||||
"vendor": "Nokia",
|
||||
"model": "1",
|
||||
"type": "mobile"
|
||||
}
|
||||
},
|
||||
{
|
||||
"desc": "Nokia3xx",
|
||||
"ua": "Nokia303/14.87 CLDC-1.1",
|
||||
|
||||
@@ -1,11 +0,0 @@
|
||||
[
|
||||
{
|
||||
"desc": "Valve",
|
||||
"ua": "Mozilla/5.0 (X11; Linux x86_64; Valve Steam Client/Steam Deck [Steam Deck Beta]/default/0) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/126.0.6478.183 Safari/537.36",
|
||||
"expect": {
|
||||
"vendor": "Valve",
|
||||
"model": "Steam Deck",
|
||||
"type": "console"
|
||||
}
|
||||
}
|
||||
]
|
||||
@@ -1,29 +0,0 @@
|
||||
[
|
||||
{
|
||||
"desc": "Wiko Life 3",
|
||||
"ua": "Mozilla/5.0 (Linux; Android 11; Wiko U316AT) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/107.0.5199.205 Mobile Safari/537.36",
|
||||
"expect": {
|
||||
"vendor": "Wiko",
|
||||
"model": "U316AT",
|
||||
"type": "mobile"
|
||||
}
|
||||
},
|
||||
{
|
||||
"desc": "Wiko Ride 3",
|
||||
"ua": "Mozilla/5.0 (Linux; Android 11; Wiko U614AS) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/88.0.4324.181 Mobile Safari/537.36",
|
||||
"expect": {
|
||||
"vendor": "Wiko",
|
||||
"model": "U614AS",
|
||||
"type": "mobile"
|
||||
}
|
||||
},
|
||||
{
|
||||
"desc": "Wiko T10",
|
||||
"ua": "Mozilla/5.0 (Linux; Android 11; WIKO T10 Build/RP1A.200720.011) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/107.0.5304.62 Mobile Safari/537.36",
|
||||
"expect": {
|
||||
"vendor": "WIKO",
|
||||
"model": "T10",
|
||||
"type": "mobile"
|
||||
}
|
||||
}
|
||||
]
|
||||
@@ -71,51 +71,6 @@
|
||||
"type": "mobile"
|
||||
}
|
||||
},
|
||||
{
|
||||
"desc": "XiaoMi Black Shark 3",
|
||||
"ua": "Mozilla/5.0 (Linux; U; Android 11; zh-CN; SHARK KLE-A0 Build/KLEN2211210CN00MR6) AppleWebKit/537.36 (KHTML, like Gecko) Version/4.0 Chrome/100.0.4896.58 UCBrowser/17.3.8.1369 Mobile Safari/537.36",
|
||||
"expect": {
|
||||
"vendor": "Xiaomi",
|
||||
"model": "SHARK KLE-A0",
|
||||
"type": "mobile"
|
||||
}
|
||||
},
|
||||
{
|
||||
"desc": "XiaoMi Black Shark 4",
|
||||
"ua": "Mozilla/5.0 (Linux; U; Android 11; en-US; SHARK PRS-H0 Build/PROS2203060OS00MP5) AppleWebKit/537.36 (KHTML, like Gecko) Version/4.0 Chrome/78.0.3904.108 UCBrowser/13.4.0.1306 Mobile Safari/537.36",
|
||||
"expect": {
|
||||
"vendor": "Xiaomi",
|
||||
"model": "SHARK PRS-H0",
|
||||
"type": "mobile"
|
||||
}
|
||||
},
|
||||
{
|
||||
"desc": "XiaoMi Black Shark 4 Pro",
|
||||
"ua": "Mozilla/5.0 (Linux; U; Android 11; es-us; SHARK KSR-H0 Build/KASE2208050OS00MP4) AppleWebKit/537.36 (KHTML, like Gecko) Version/4.0 Chrome/100.0.4896.127 Mobile Safari/537.36 XiaoMi/MiuiBrowser/13.22.1-gn",
|
||||
"expect": {
|
||||
"vendor": "Xiaomi",
|
||||
"model": "SHARK KSR-H0",
|
||||
"type": "mobile"
|
||||
}
|
||||
},
|
||||
{
|
||||
"desc": "XiaoMi Black Shark 5",
|
||||
"ua": "Mozilla/5.0 (Linux; arm_64; Android 12; SHARK PAR-H0) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/112.0.0.0 YaBrowser/23.5.0.256.00 SA/3 Mobile Safari/537.36",
|
||||
"expect": {
|
||||
"vendor": "Xiaomi",
|
||||
"model": "SHARK PAR-H0",
|
||||
"type": "mobile"
|
||||
}
|
||||
},
|
||||
{
|
||||
"desc": "XiaoMi Civi 5 Pro",
|
||||
"ua": "Mozilla/5.0 (Linux; U; Android 15; zh-CN; 25067PYE3C Build/AQ3A.250129.001) AppleWebKit/537.36 (KHTML, like Gecko) Version/4.0 Chrome/100.0.4896.58 UCBrowser/18.0.4.1430 Mobile Safari/537.36",
|
||||
"expect": {
|
||||
"vendor": "Xiaomi",
|
||||
"model": "25067PYE3C",
|
||||
"type": "mobile"
|
||||
}
|
||||
},
|
||||
{
|
||||
"desc": "Xiaomi Hongmi Note 1W",
|
||||
"ua": "Mozilla/5.0 (Linux; U; Android 4.2.2; zh-CN; HM NOTE 1W Build/JDQ39) AppleWebKit/533.1 (KHTML, like Gecko) Version/4.0 UCBrowser/9.7.9.439 U3/0.8.0 Mobile Safari/533.1",
|
||||
@@ -161,15 +116,6 @@
|
||||
"type": "mobile"
|
||||
}
|
||||
},
|
||||
{
|
||||
"desc": "Xiaomi Mi 11 Lite 5G",
|
||||
"ua": "Mozilla/5.0 (Linux; U; Android 12; zh-CN; Mi 11 Lite 5G Build/SKQ1.211006.001) AppleWebKit/537.36 (KHTML, like Gecko) Version/4.0 Chrome/100.0.4896.136 Mobile Safari/537.36 XiaoMi/MiuiBrowser/13.17.0-gn",
|
||||
"expect": {
|
||||
"vendor": "Xiaomi",
|
||||
"model": "Mi 11 Lite 5G",
|
||||
"type": "mobile"
|
||||
}
|
||||
},
|
||||
{
|
||||
"desc": "Xiaomi Mi 5s Plus",
|
||||
"ua": "Mozilla/5.0 (Linux; U; Android 6.0.1; zh-cn; MI 5s Plus Build/MXB48T) AppleWebKit/537.36 (KHTML, like Gecko) Version/4.0 Chrome/53.0.2785.146 Mobile Safari/537.36 XiaoMi/MiuiBrowser/8.7.1",
|
||||
@@ -242,15 +188,6 @@
|
||||
"type": "mobile"
|
||||
}
|
||||
},
|
||||
{
|
||||
"desc": "Xiaomi Mi 10T",
|
||||
"ua": "Mozilla/5.0 (Linux; U; Android 12; fr-CA; Mi 10T Build/SKQ1.211006.001) AppleWebKit/537.36 (KHTML, like Gecko) Version/4.0 Chrome/100.0.4896.79 Mobile Safari/537.36 XiaoMi/MiuiBrowser/13.16.1-gn",
|
||||
"expect": {
|
||||
"vendor": "Xiaomi",
|
||||
"model": "Mi 10T",
|
||||
"type": "mobile"
|
||||
}
|
||||
},
|
||||
{
|
||||
"desc": "Xiaomi Mi A2",
|
||||
"ua": "Mozilla/5.0 (Linux; Android 9; Mi A2) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/76.0.3809.132 Mobile Safari/537.36",
|
||||
@@ -377,15 +314,6 @@
|
||||
"type": "tablet"
|
||||
}
|
||||
},
|
||||
{
|
||||
"desc": "Xiaomi Pad 5",
|
||||
"ua": "Mozilla/5.0 (Linux; U; Android 12; ca-ES; Xiaomi Pad 5 Build/SKQ1.220303.001) AppleWebKit/537.36 (KHTML, like Gecko) Version/4.0 Chrome/89.0.4389.86 Mobile Safari/537.36 XiaoMi/MiuiBrowser/13.6.0-gn",
|
||||
"expect": {
|
||||
"vendor": "Xiaomi",
|
||||
"model": "mi Pad 5",
|
||||
"type": "tablet"
|
||||
}
|
||||
},
|
||||
{
|
||||
"desc": "Xiaomi Pad 6S Pro 12.4",
|
||||
"ua": "Mozilla/5.0 (Linux; Android 14; 24018RPACC) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/110.0.0.0 Safari/537.36",
|
||||
@@ -458,42 +386,6 @@
|
||||
"type": "mobile"
|
||||
}
|
||||
},
|
||||
{
|
||||
"desc": "Xiaomi Qin 1s+",
|
||||
"ua": "Mozilla/5.0 (Linux; U; Android 4.4.4; Qin 1s+ Build/KTU84P; wv) AppleWebKit/537.36 (KHTML, like Gecko) Version/4.0 Chrome/33.0.0.0 Mobile Safari/537.36 OPR/46.0.2254.145391",
|
||||
"expect": {
|
||||
"vendor": "Xiaomi",
|
||||
"model": "Qin 1s+",
|
||||
"type": "mobile"
|
||||
}
|
||||
},
|
||||
{
|
||||
"desc": "Xiaomi Qin 2",
|
||||
"ua": "Mozilla/5.0 (Linux; Android 9; Qin 2) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/80.0.3987.162 Mobile Safari/537.36",
|
||||
"expect": {
|
||||
"vendor": "Xiaomi",
|
||||
"model": "Qin 2",
|
||||
"type": "mobile"
|
||||
}
|
||||
},
|
||||
{
|
||||
"desc": "Xiaomi Qin 2 Pro",
|
||||
"ua": "Mozilla/5.0 (Linux; Android 9.0; QIN2 Pro) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/86.0.4215.0 Mobile Safari/537.36 EdgA/86.0.597.0",
|
||||
"expect": {
|
||||
"vendor": "Xiaomi",
|
||||
"model": "QIN2 Pro",
|
||||
"type": "mobile"
|
||||
}
|
||||
},
|
||||
{
|
||||
"desc": "Xiaomi Qin 3 Ultra",
|
||||
"ua": "Mozilla/5.0 (Linux; Android 12; QIN3ULTRA Build/SP1A.210812.016; wv) AppleWebKit/537.36 (KHTML, like Gecko) Version/4.0 Chrome/128.0.6613.120 Mobile Safari/537.36",
|
||||
"expect": {
|
||||
"vendor": "Xiaomi",
|
||||
"model": "QIN3ULTRA",
|
||||
"type": "mobile"
|
||||
}
|
||||
},
|
||||
{
|
||||
"desc": "Xiaomi Redmi 4A",
|
||||
"ua": "Mozilla/5.0 (Linux; Android 6.0; Redmi 4A Build/MMB29M; xx-xx) AppleWebKit/537.36 (KHTML, like Gecko) Version/4.0 Chrome/56.0.2924.87 Mobile Safari/537.36",
|
||||
@@ -512,15 +404,6 @@
|
||||
"type": "mobile"
|
||||
}
|
||||
},
|
||||
{
|
||||
"desc": "Xiaomi Redmi 15",
|
||||
"ua": "Mozilla/5.0 (Linux; Android 15; 25062RN2DA Build/AQ3A.250226.002; wv) AppleWebKit/537.36 (KHTML, like Gecko) Version/4.0 Chrome/142.0.7444.212 Mobile Safari/537.36 [FB_IAB/FB4A;FBAV/541.0.0.49.79;IABMV/1;]",
|
||||
"expect": {
|
||||
"vendor": "Xiaomi",
|
||||
"model": "25062RN2DA",
|
||||
"type": "mobile"
|
||||
}
|
||||
},
|
||||
{
|
||||
"desc": "Xiaomi Redmi K30 5G",
|
||||
"ua": "Mozilla/5.0 (Linux; Android 10; Redmi K30 5G) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/78.0.3904.96 Mobile Safari/537.36",
|
||||
@@ -575,15 +458,6 @@
|
||||
"type": "mobile"
|
||||
}
|
||||
},
|
||||
{
|
||||
"desc": "XiaoMi Redmi Note 10 Lite",
|
||||
"ua": "Mozilla/5.0 (Linux; U; Android 12; es-VE; Mi Note 10 Lite Build/SKQ1.210908.001) AppleWebKit/537.36 (KHTML, like Gecko) Version/4.0 Chrome/100.0.4896.88 Mobile Safari/537.36 XiaoMi/MiuiBrowser/13.16.1-gn",
|
||||
"expect": {
|
||||
"vendor": "Xiaomi",
|
||||
"model": "Mi Note 10 Lite",
|
||||
"type": "mobile"
|
||||
}
|
||||
},
|
||||
{
|
||||
"desc": "XiaoMi Redmi Note 10 Pro",
|
||||
"ua": "Mozilla/5.0 (Linux; Android 13; M2101K6P) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/107.0.0.0 Mobile Safari/537.36",
|
||||
@@ -691,14 +565,5 @@
|
||||
"model": "MIBOX3",
|
||||
"type": "smarttv"
|
||||
}
|
||||
},
|
||||
{
|
||||
"desc": "Xiaomi Watch 2 Pro",
|
||||
"ua": "Dalvik/2.1.0 (Linux; U; Android 13; Xiaomi Watch 2 Pro Build/TWR7.231031.001.XM064S)",
|
||||
"expect": {
|
||||
"vendor": "Xiaomi",
|
||||
"model": "Watch 2 Pro",
|
||||
"type": "wearable"
|
||||
}
|
||||
}
|
||||
]
|
||||
@@ -965,7 +965,7 @@
|
||||
"ua" : "Mozilla/5.0 (compatible; Qwantbot-news/2.0; +https://help.qwant.com/bot/)",
|
||||
"expect" :
|
||||
{
|
||||
"name" : "Qwantbot-news",
|
||||
"name" : "Qwantbot",
|
||||
"version" : "2.0",
|
||||
"type" : "crawler"
|
||||
}
|
||||
@@ -1100,26 +1100,6 @@
|
||||
"type" : "crawler"
|
||||
}
|
||||
},
|
||||
{
|
||||
"desc" : "SurdotlyBot",
|
||||
"ua" : "Mozilla/5.0 (compatible; SurdotlyBot/1.0; +http://sur.ly/bot.html)",
|
||||
"expect" :
|
||||
{
|
||||
"name" : "SurdotlyBot",
|
||||
"version" : "1.0",
|
||||
"type" : "crawler"
|
||||
}
|
||||
},
|
||||
{
|
||||
"desc" : "Swiftbot",
|
||||
"ua" : "Swiftbot/1.0 (swiftype.com)",
|
||||
"expect" :
|
||||
{
|
||||
"name" : "Swiftbot",
|
||||
"version" : "1.0",
|
||||
"type" : "crawler"
|
||||
}
|
||||
},
|
||||
{
|
||||
"desc" : "Teoma",
|
||||
"ua" : "Mozilla/2.0 (compatible; Ask Jeeves/Teoma; +http://sp.ask.com/docs/about/tech_crawling.html)",
|
||||
|
||||
@@ -51,7 +51,7 @@
|
||||
},
|
||||
{
|
||||
"desc" : "Blueno",
|
||||
"ua" : "facebookexternalhit/1.1 (compatible; Blueno/1.0; +http://naver.me/scrap)",
|
||||
"ua" : "acebookexternalhit/1.1 (compatible; Blueno/1.0; +http://naver.me/scrap)",
|
||||
"expect" :
|
||||
{
|
||||
"name" : "Blueno",
|
||||
@@ -119,16 +119,6 @@
|
||||
"type" : "fetcher"
|
||||
}
|
||||
},
|
||||
{
|
||||
"desc" : "Discordbot",
|
||||
"ua" : "Mozilla/5.0 (compatible; Discordbot/2.0; +https://discordapp.com)",
|
||||
"expect" :
|
||||
{
|
||||
"name" : "Discordbot",
|
||||
"version" : "2.0",
|
||||
"type" : "fetcher"
|
||||
}
|
||||
},
|
||||
{
|
||||
"desc" : "DuckAssistBot",
|
||||
"ua" : "DuckAssistBot/1.2; (+http://duckduckgo.com/duckassistbot.html)",
|
||||
@@ -249,16 +239,6 @@
|
||||
"type" : "fetcher"
|
||||
}
|
||||
},
|
||||
{
|
||||
"desc" : "KeybaseBot",
|
||||
"ua" : "Mozilla/5.0 (compatible; KeybaseBot; +https://keybase.io)",
|
||||
"expect" :
|
||||
{
|
||||
"name" : "KeybaseBot",
|
||||
"version" : "undefined",
|
||||
"type" : "fetcher"
|
||||
}
|
||||
},
|
||||
{
|
||||
"desc" : "Meta-ExternalFetcher",
|
||||
"ua" : "meta-externalfetcher/1.1 (+https://developers.facebook.com/docs/sharing/webmasters/crawler)",
|
||||
@@ -289,16 +269,6 @@
|
||||
"type" : "fetcher"
|
||||
}
|
||||
},
|
||||
{
|
||||
"desc" : "NovaAct",
|
||||
"ua" : "Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/115.0.0.0 Safari/537.36 Agent-NovaAct/0.9",
|
||||
"expect" :
|
||||
{
|
||||
"name" : "NovaAct",
|
||||
"version" : "0.9",
|
||||
"type" : "fetcher"
|
||||
}
|
||||
},
|
||||
{
|
||||
"desc" : "Perplexity-User",
|
||||
"ua" : "Mozilla/5.0 AppleWebKit/537.36 (KHTML, like Gecko; compatible; Perplexity-User/1.0; +https://perplexity.ai/perplexity-user)",
|
||||
@@ -339,36 +309,6 @@
|
||||
"type" : "fetcher"
|
||||
}
|
||||
},
|
||||
{
|
||||
"desc" : "Slack-ImgProxy",
|
||||
"ua" : "Slack-ImgProxy 0.19 (+https://api.slack.com/robots)",
|
||||
"expect" :
|
||||
{
|
||||
"name" : "Slack-ImgProxy",
|
||||
"version" : "0.19",
|
||||
"type" : "fetcher"
|
||||
}
|
||||
},
|
||||
{
|
||||
"desc" : "Slackbot",
|
||||
"ua" : "Slackbot 1.0 (+https://api.slack.com/robots)",
|
||||
"expect" :
|
||||
{
|
||||
"name" : "Slackbot",
|
||||
"version" : "1.0",
|
||||
"type" : "fetcher"
|
||||
}
|
||||
},
|
||||
{
|
||||
"desc" : "Slackbot-LinkExpanding",
|
||||
"ua" : "Slackbot-LinkExpanding 1.0 (+https://api.slack.com/robots)",
|
||||
"expect" :
|
||||
{
|
||||
"name" : "Slackbot-LinkExpanding",
|
||||
"version" : "1.0",
|
||||
"type" : "fetcher"
|
||||
}
|
||||
},
|
||||
{
|
||||
"desc" : "Snap URL Preview",
|
||||
"ua" : "Snap URL Preview Service; bot; snapchat; https://developers.snap.com/robots ",
|
||||
@@ -399,16 +339,6 @@
|
||||
"type" : "fetcher"
|
||||
}
|
||||
},
|
||||
{
|
||||
"desc" : "Twitterbot",
|
||||
"ua" : "Twitterbot/1.0",
|
||||
"expect" :
|
||||
{
|
||||
"name" : "Twitterbot",
|
||||
"version" : "1.0",
|
||||
"type" : "fetcher"
|
||||
}
|
||||
},
|
||||
{
|
||||
"desc" : "UptimeRobot",
|
||||
"ua" : "Mozilla/5.0 (compatible; UptimeRobot/2.0; http://www.uptimerobot.com/)",
|
||||
|
||||
@@ -39,36 +39,6 @@
|
||||
"type" : "library"
|
||||
}
|
||||
},
|
||||
{
|
||||
"desc" : "Bun",
|
||||
"ua" : "Bun/1.0.6",
|
||||
"expect" :
|
||||
{
|
||||
"name" : "Bun",
|
||||
"version" : "1.0.6",
|
||||
"type" : "library"
|
||||
}
|
||||
},
|
||||
{
|
||||
"desc" : "Dart",
|
||||
"ua" : "Dart/3.5 (dart:io)",
|
||||
"expect" :
|
||||
{
|
||||
"name" : "Dart",
|
||||
"version" : "3.5",
|
||||
"type" : "library"
|
||||
}
|
||||
},
|
||||
{
|
||||
"desc" : "Deno",
|
||||
"ua" : "Deno/2.1.7",
|
||||
"expect" :
|
||||
{
|
||||
"name" : "Deno",
|
||||
"version" : "2.1.7",
|
||||
"type" : "library"
|
||||
}
|
||||
},
|
||||
{
|
||||
"desc" : "go-http-client",
|
||||
"ua" : "go-http-client/1.1",
|
||||
@@ -89,16 +59,6 @@
|
||||
"type" : "library"
|
||||
}
|
||||
},
|
||||
{
|
||||
"desc" : "hackney",
|
||||
"ua" : "hackney/1.20.1",
|
||||
"expect" :
|
||||
{
|
||||
"name" : "hackney",
|
||||
"version" : "1.20.1",
|
||||
"type" : "library"
|
||||
}
|
||||
},
|
||||
{
|
||||
"desc" : "GuzzleHttp",
|
||||
"ua" : "GuzzleHttp/6.5.5 curl/7.70.0 PHP/7.4.22",
|
||||
@@ -169,26 +129,6 @@
|
||||
"type" : "library"
|
||||
}
|
||||
},
|
||||
{
|
||||
"desc" : "Node.js",
|
||||
"ua" : "Node.js/22",
|
||||
"expect" :
|
||||
{
|
||||
"name" : "Node.js",
|
||||
"version" : "22",
|
||||
"type" : "library"
|
||||
}
|
||||
},
|
||||
{
|
||||
"desc" : "node-fetch",
|
||||
"ua" : "node-fetch/1.0 (+https://github.com/bitinn/node-fetch)",
|
||||
"expect" :
|
||||
{
|
||||
"name" : "node-fetch",
|
||||
"version" : "1.0",
|
||||
"type" : "library"
|
||||
}
|
||||
},
|
||||
{
|
||||
"desc" : "Nutch",
|
||||
"ua" : "AliyunSecBot/Nutch-1.21-SNAPSHOT",
|
||||
@@ -209,6 +149,16 @@
|
||||
"type" : "library"
|
||||
}
|
||||
},
|
||||
{
|
||||
"desc" : "node-fetch",
|
||||
"ua" : "node-fetch/1.0 (+https://github.com/bitinn/node-fetch)",
|
||||
"expect" :
|
||||
{
|
||||
"name" : "node-fetch",
|
||||
"version" : "1.0",
|
||||
"type" : "library"
|
||||
}
|
||||
},
|
||||
{
|
||||
"desc" : "PHP-SOAP",
|
||||
"ua" : "PHP-SOAP/7.4.33",
|
||||
@@ -269,16 +219,6 @@
|
||||
"type" : "library"
|
||||
}
|
||||
},
|
||||
{
|
||||
"desc" : "rest-client",
|
||||
"ua" : "rest-client/2.1.0 (linux-gnu x86_64) ruby/2.7.2p137",
|
||||
"expect" :
|
||||
{
|
||||
"name" : "rest-client",
|
||||
"version" : "2.1.0",
|
||||
"type" : "library"
|
||||
}
|
||||
},
|
||||
{
|
||||
"desc" : "Scrapy",
|
||||
"ua" : "Scrapy/1.5.0 (+https://scrapy.org)",
|
||||
@@ -298,15 +238,5 @@
|
||||
"version" : "5.0.2",
|
||||
"type" : "library"
|
||||
}
|
||||
},
|
||||
{
|
||||
"desc" : "undici",
|
||||
"ua" : "undici",
|
||||
"expect" :
|
||||
{
|
||||
"name" : "undici",
|
||||
"version" : "undefined",
|
||||
"type" : "library"
|
||||
}
|
||||
}
|
||||
]
|
||||
|
||||
@@ -1,22 +1,4 @@
|
||||
[
|
||||
{
|
||||
"desc" : "iOS 18.6",
|
||||
"ua" : "Mozilla/5.0 (iPhone; CPU iPhone OS 18_6 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/18.6 Mobile/15E148 Safari/604.1",
|
||||
"expect" :
|
||||
{
|
||||
"name" : "iOS",
|
||||
"version" : "18.6"
|
||||
}
|
||||
},
|
||||
{
|
||||
"desc" : "iOS 26",
|
||||
"ua" : "Mozilla/5.0 (iPhone; CPU iPhone OS 18_6 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/26.0 Mobile/15E148 Safari/604.1",
|
||||
"expect" :
|
||||
{
|
||||
"name" : "iOS",
|
||||
"version" : "26.0"
|
||||
}
|
||||
},
|
||||
{
|
||||
"desc" : "iOS in App",
|
||||
"ua" : "AppName/version CFNetwork/version Darwin/version",
|
||||
@@ -35,15 +17,6 @@
|
||||
"version" : "5.1.1"
|
||||
}
|
||||
},
|
||||
{
|
||||
"desc" : "iOS with DuckDuckGo",
|
||||
"ua" : "Mozilla/5.0 (iPhone; CPU iPhone OS 18_7 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/26.0 Mobile/15E148 Safari/604.1 Ddg/26.0",
|
||||
"expect" :
|
||||
{
|
||||
"name" : "iOS",
|
||||
"version" : "18.7"
|
||||
}
|
||||
},
|
||||
{
|
||||
"desc" : "iOS with Opera Mini",
|
||||
"ua" : "Opera/9.80 (iPhone; Opera Mini/7.1.32694/27.1407; U; en) Presto/2.8.119 Version/11.10",
|
||||
@@ -62,33 +35,6 @@
|
||||
"version" : "13.6.1"
|
||||
}
|
||||
},
|
||||
{
|
||||
"desc": "iOS with Instagram",
|
||||
"ua": "Instagram 5.0.2 (iPhone5,1; iPhone OS 7_0_4; en_US; en) AppleWebKit/420+",
|
||||
"expect":
|
||||
{
|
||||
"name" : "iOS",
|
||||
"version" : "7.0.4"
|
||||
}
|
||||
},
|
||||
{
|
||||
"desc": "iOS with MS Word App",
|
||||
"ua": "Microsoft Office Word/2.44.1211 (iOS/13.7; Tablet; es-MX; AppStore; Apple/iPad11,3)",
|
||||
"expect":
|
||||
{
|
||||
"name" : "iOS",
|
||||
"version" : "13.7"
|
||||
}
|
||||
},
|
||||
{
|
||||
"desc": "iOS with Quora App",
|
||||
"ua": "Quora 8.4.30 rv:3230 env:prod (iPad11,3; iPadOS 17.7; en_GB) AppleWebKit",
|
||||
"expect":
|
||||
{
|
||||
"name" : "iOS",
|
||||
"version" : "17.7"
|
||||
}
|
||||
},
|
||||
{
|
||||
"desc": "iOS with Slack App",
|
||||
"ua": "com.tinyspeck.chatlyio/23.04.10 (iPhone; iOS 16.4.1; Scale/3.00)",
|
||||
@@ -98,33 +44,6 @@
|
||||
"version" : "16.4.1"
|
||||
}
|
||||
},
|
||||
{
|
||||
"desc": "iOS with Snapchat",
|
||||
"ua": "Snapchat/12.12.1.40 (iPhone15,2; iOS 16.2; gzip)",
|
||||
"expect":
|
||||
{
|
||||
"name" : "iOS",
|
||||
"version" : "16.2"
|
||||
}
|
||||
},
|
||||
{
|
||||
"desc": "iOS with Spotify App",
|
||||
"ua": "Spotify/8.7.70 iOS/16.0 (iPhone15,3)",
|
||||
"expect":
|
||||
{
|
||||
"name" : "iOS",
|
||||
"version" : "16.0"
|
||||
}
|
||||
},
|
||||
{
|
||||
"desc": "iOS with TuneIn Radio App",
|
||||
"ua": "TuneIn Radio/27.1.0; iPad6,3; iPadOS/16.6",
|
||||
"expect":
|
||||
{
|
||||
"name" : "iOS",
|
||||
"version" : "16.6"
|
||||
}
|
||||
},
|
||||
{
|
||||
"desc" : "iOS BE App",
|
||||
"ua" : "APP-BE Test/1.0 (iPad; Apple; CPU iPhone OS 7_0_2 like Mac OS X)",
|
||||
@@ -142,41 +61,5 @@
|
||||
"name" : "iOS",
|
||||
"version" : "11.2.5"
|
||||
}
|
||||
},
|
||||
{
|
||||
"desc": "iOS",
|
||||
"ua": "iPlayTV/3.3.9 (Apple TV; iOS 16.1; Scale/1.00)",
|
||||
"expect" :
|
||||
{
|
||||
"name" : "iOS",
|
||||
"version" : "16.1"
|
||||
}
|
||||
},
|
||||
{
|
||||
"desc": "iOS",
|
||||
"ua": "itunesstored/1.0 iOS/8.4.4 AppleTV/7.8 model/AppleTV3,2 build/12H937 (3; dt:12)",
|
||||
"expect" :
|
||||
{
|
||||
"name" : "iOS",
|
||||
"version" : "8.4.4"
|
||||
}
|
||||
},
|
||||
{
|
||||
"desc": "tvOS",
|
||||
"ua": "iMPlayer/1.6.1 (tvOS 26.0.1)",
|
||||
"expect" :
|
||||
{
|
||||
"name" : "iOS",
|
||||
"version" : "26.0.1"
|
||||
}
|
||||
},
|
||||
{
|
||||
"desc": "tvOS",
|
||||
"ua": "otg/1.5.1 (AppleTv Apple TV 4; tvOS16.2; appletv.client) libcurl/7.58.0 OpenSSL/1.0.2o zlib/1.2.11 clib/1.8.56",
|
||||
"expect" :
|
||||
{
|
||||
"name" : "iOS",
|
||||
"version" : "16.2"
|
||||
}
|
||||
}
|
||||
]
|
||||
@@ -152,45 +152,3 @@ test.describe('request.headers can be passed in form of a Headers object', () =>
|
||||
expect(uap.ua).toBe('myBrowser/1.0');
|
||||
});
|
||||
});
|
||||
|
||||
test.describe('Chaining withFeatureCheck() & withClientHints() in client-side development', () => {
|
||||
|
||||
test('Chain', async ({ page, browserName }) => {
|
||||
await page.addInitScript((browserName) => {
|
||||
Object.defineProperty(navigator, 'userAgent', {
|
||||
value: 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/16.0 Safari/605.1.15'
|
||||
});
|
||||
Object.defineProperty(navigator, 'standalone', {
|
||||
value: true
|
||||
});
|
||||
Object.defineProperty(navigator, 'maxTouchPoints', {
|
||||
value: 3
|
||||
});
|
||||
if (browserName == 'chromium') {
|
||||
Object.defineProperty(navigator, 'userAgentData', {
|
||||
value: {
|
||||
brands: [],
|
||||
platform: '',
|
||||
mobile: false,
|
||||
getHighEntropyValues: () => {
|
||||
return Promise.resolve({
|
||||
formFactors: 'VR'
|
||||
});
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
}, browserName);
|
||||
await page.goto(localHtml);
|
||||
// @ts-ignore
|
||||
const fc2ch = await page.evaluate(async () => await UAParser().withFeatureCheck().then(res => res.withClientHints()));
|
||||
const ch2fc = await page.evaluate(async () => await UAParser().withClientHints().then(res => res.withFeatureCheck()));
|
||||
if (browserName == 'chromium') {
|
||||
expect(fc2ch).toHaveProperty('device.type', 'xr'); // overwrite by client hints
|
||||
expect(ch2fc).toHaveProperty('device.type', 'tablet'); // overwrite by feature check
|
||||
} else {
|
||||
expect(fc2ch).toHaveProperty('device.type', 'tablet'); // no client hints found
|
||||
expect(ch2fc).toHaveProperty('device.type', 'tablet');
|
||||
}
|
||||
});
|
||||
});
|
||||
@@ -1,37 +0,0 @@
|
||||
const assert = require('node:assert');
|
||||
const { exec } = require('node:child_process');
|
||||
const fs = require('node:fs');
|
||||
const { UAParser } = require('../../../src/main/ua-parser');
|
||||
const uap = new UAParser();
|
||||
|
||||
const input = [
|
||||
'Opera/9.25 (Windows NT 6.0; U; ru)',
|
||||
'Mozilla/4.0 (compatible; MSIE 5.5; Windows NT)'
|
||||
];
|
||||
const output = input.map(x => uap.setUA(x).getResult());
|
||||
|
||||
describe('npx ua-parser-js <string>', () => {
|
||||
it ('print result to stdout', () => {
|
||||
exec('npx ua-parser-js "TEST"', (err, stdout, stderr) => {
|
||||
assert.deepEqual(JSON.parse(stdout), JSON.parse(JSON.stringify([uap.setUA("TEST").getResult()])));
|
||||
});
|
||||
})
|
||||
});
|
||||
|
||||
describe('npx ua-parser-js --input-file=<filepath>', () => {
|
||||
it ('load file and print result to stdout', () => {
|
||||
exec('npx ua-parser-js --input-file="../test/unit/cli/input.txt"', (err, stdout, stderr) => {
|
||||
assert.deepEqual(JSON.parse(stdout), JSON.parse(JSON.stringify(output)));
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
describe('npx ua-parser-js --input-file=<filepath> --output-file=<filepath>', () => {
|
||||
it ('load file and save result to file', () => {
|
||||
exec('npx ua-parser-js --input-file="../test/unit/cli/input.txt" --output-file="../test/unit/cli/output.json"', (err, stdout, stderr) => {
|
||||
fs.readFile('test/unit/cli/output.json', (err, data) => {
|
||||
assert.deepEqual(JSON.parse(data), JSON.parse(JSON.stringify(output)));
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
@@ -1,2 +0,0 @@
|
||||
Opera/9.25 (Windows NT 6.0; U; ru)
|
||||
Mozilla/4.0 (compatible; MSIE 5.5; Windows NT)
|
||||
@@ -1,32 +0,0 @@
|
||||
[
|
||||
{
|
||||
"ua": "Opera/9.25 (Windows NT 6.0; U; ru)",
|
||||
"browser": {
|
||||
"name": "Opera",
|
||||
"version": "9.25",
|
||||
"major": "9"
|
||||
},
|
||||
"cpu": {},
|
||||
"device": {},
|
||||
"engine": {},
|
||||
"os": {
|
||||
"name": "Windows",
|
||||
"version": "Vista"
|
||||
}
|
||||
},
|
||||
{
|
||||
"ua": "Mozilla/4.0 (compatible; MSIE 5.5; Windows NT)",
|
||||
"browser": {
|
||||
"name": "IE",
|
||||
"version": "5.5",
|
||||
"major": "5"
|
||||
},
|
||||
"cpu": {},
|
||||
"device": {},
|
||||
"engine": {},
|
||||
"os": {
|
||||
"name": "Windows",
|
||||
"version": "NT"
|
||||
}
|
||||
}
|
||||
]
|
||||
@@ -3,9 +3,9 @@ const assert = require('assert');
|
||||
const parseJS = require('@babel/parser').parse;
|
||||
const traverse = require('@babel/traverse').default;
|
||||
const safe = require('safe-regex');
|
||||
const { UAParser } = require('../../../src/main/ua-parser');
|
||||
const { Bots, CLIs, Crawlers, Emails, Fetchers, InApps, Libraries, Vehicles } = require('../../../src/extensions/ua-parser-extensions');
|
||||
const { BrowserType, OSName, Extension } = require('../../../src/enums/ua-parser-enums');
|
||||
const { UAParser } = require('../../src/main/ua-parser');
|
||||
const { Bots, CLIs, Crawlers, Emails, Fetchers, InApps, Libraries, Vehicles } = require('../../src/extensions/ua-parser-extensions');
|
||||
const { BrowserType, OSName, Extension } = require('../../src/enums/ua-parser-enums');
|
||||
const { CLI, Crawler, Email, Fetcher, Library } = Extension.BrowserName;
|
||||
|
||||
describe('Extensions', () => {
|
||||
@@ -19,7 +19,7 @@ describe('Extensions', () => {
|
||||
['Vehicles', 'vehicle', Vehicles]
|
||||
]
|
||||
.forEach(([desc, path, ext]) => {
|
||||
const tests = require(`../../data/ua/extension/${path}.json`);
|
||||
const tests = require(`../data/ua/extension/${path}.json`);
|
||||
describe(desc, () => {
|
||||
tests.forEach((test) => {
|
||||
it(`Can detect ${test.desc}: "${test.ua}"`, () => {
|
||||
85
test/unit/helpers.js
Normal file
85
test/unit/helpers.js
Normal file
@@ -0,0 +1,85 @@
|
||||
const assert = require('assert');
|
||||
const { UAParser } = require('../../src/main/ua-parser');
|
||||
const { getDeviceVendor, isAppleSilicon, isAIBot, isBot, isChromeFamily } = require('../../src/helpers/ua-parser-helpers');
|
||||
const { Bots, Emails } = require('../../src/extensions/ua-parser-extensions');
|
||||
const { DeviceVendor } = require('../../src/enums/ua-parser-enums');
|
||||
|
||||
describe('getDeviceVendor', () => {
|
||||
it('Can guess the device vendor from a model name', () => {
|
||||
|
||||
const modelSM = 'SM-A605G';
|
||||
const modelRedmi = 'Redmi Note 8';
|
||||
const modelNexus = 'Nexus 6P';
|
||||
const modelAquos = 'AQUOS-TVX19B';
|
||||
|
||||
assert.equal(getDeviceVendor(modelSM), DeviceVendor.SAMSUNG);
|
||||
assert.equal(getDeviceVendor(modelRedmi), DeviceVendor.XIAOMI);
|
||||
assert.equal(getDeviceVendor(modelNexus), DeviceVendor.HUAWEI);
|
||||
assert.equal(getDeviceVendor(modelAquos), DeviceVendor.SHARP);
|
||||
});
|
||||
});
|
||||
|
||||
describe('isAppleSilicon', () => {
|
||||
it('Can detect Apple Silicon device', () => {
|
||||
|
||||
// non-real ua
|
||||
const macARM = 'Mozilla/5.0 (Macintosh; ARM; Mac OS X 10.15; rv:97.0) Gecko/20100101 Firefox/97.0';
|
||||
const macIntel = 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10.15; rv:97.0) Gecko/20100101 Firefox/97.0';
|
||||
|
||||
assert.equal(isAppleSilicon(UAParser(macIntel)), false);
|
||||
assert.equal(isAppleSilicon(macIntel), false);
|
||||
assert.equal(isAppleSilicon(UAParser(macARM)), true);
|
||||
assert.equal(isAppleSilicon(macARM), true);
|
||||
});
|
||||
});
|
||||
|
||||
describe('isAIBot', () => {
|
||||
it('Can detect AI Bots', () => {
|
||||
|
||||
const claudeBot = 'Mozilla/5.0 AppleWebKit/537.36 (KHTML, like Gecko; compatible; ClaudeBot/1.0; +claudebot@anthropic.com)';
|
||||
const firefox = 'Mozilla/5.0 (X11; Linux x86_64; rv:109.0) Gecko/20100101 Firefox/111.0';
|
||||
const searchGPT = 'Mozilla/5.0 AppleWebKit/537.36 (KHTML, like Gecko); compatible; OAI-SearchBot/1.0; +https://openai.com/searchbot';
|
||||
const semrushAI = 'Mozilla/5.0 (compatible; SemrushBot-OCOB/1; +https://www.semrush.com/bot/)';
|
||||
|
||||
assert.equal(isAIBot(UAParser(claudeBot, Bots)), true);
|
||||
assert.equal(isAIBot(claudeBot), true);
|
||||
assert.equal(isAIBot(firefox), false);
|
||||
assert.equal(isAIBot(searchGPT), true);
|
||||
assert.equal(isAIBot(semrushAI), true);
|
||||
});
|
||||
});
|
||||
|
||||
describe('isBot', () => {
|
||||
it('Can detect Bots', () => {
|
||||
|
||||
// non-real ua
|
||||
const ahrefsBot = 'Mozilla/5.0 (compatible; AhrefsBot/7.0; +http://ahrefs.com/robot/)';
|
||||
const firefox = 'Mozilla/5.0 (X11; Linux x86_64; rv:109.0) Gecko/20100101 Firefox/111.0';
|
||||
const scrapy = 'Scrapy/1.5.0 (+https://scrapy.org)';
|
||||
const thunderbird = 'Mozilla/5.0 (X11; Linux x86_64; rv:78.0) Gecko/20100101 Thunderbird/78.13.0';
|
||||
|
||||
const botParser = new UAParser(firefox, { Bots, Emails });
|
||||
assert.equal(isBot(botParser.getResult()), false);
|
||||
assert.equal(isBot(botParser.setUA(ahrefsBot).getResult()), true);
|
||||
assert.equal(isBot(botParser.setUA(scrapy).getResult()), true);
|
||||
assert.equal(isBot(botParser.setUA(thunderbird).getResult()), false);
|
||||
|
||||
assert.equal(isBot(ahrefsBot), true);
|
||||
assert.equal(isBot(firefox), false);
|
||||
assert.equal(isBot(scrapy), true);
|
||||
assert.equal(isBot(thunderbird), false);
|
||||
});
|
||||
});
|
||||
|
||||
describe('isChromeFamily', () => {
|
||||
it('Can detect Chromium-based browser', () => {
|
||||
|
||||
const edge = 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/119.0.0.0 Safari/537.36 Edg/119.0.2151.58';
|
||||
const firefox = 'Mozilla/5.0 (X11; Linux x86_64; rv:109.0) Gecko/20100101 Firefox/111.0';
|
||||
|
||||
assert.equal(isChromeFamily(UAParser(edge)), true);
|
||||
assert.equal(isChromeFamily(UAParser(firefox)), false);
|
||||
assert.equal(isChromeFamily(edge), true);
|
||||
assert.equal(isChromeFamily(firefox), false);
|
||||
});
|
||||
});
|
||||
@@ -10,6 +10,7 @@ var cpus = require('../data/ua/cpu/cpu-all.json');
|
||||
var devices = readJsonFiles('test/data/ua/device');
|
||||
var engines = require('../data/ua/engine/engine-all.json');
|
||||
var os = readJsonFiles('test/data/ua/os');
|
||||
var { Headers } = require('undici');
|
||||
|
||||
function readJsonFiles(dir) {
|
||||
var list = [];
|
||||
@@ -162,14 +163,6 @@ describe('Extending Regex', function () {
|
||||
assert.deepEqual(myParser3.setUA(myUA2).getDevice(), {vendor: "MyTab", model: "14 Pro Max", type: "tablet"});
|
||||
});
|
||||
|
||||
describe('User-agent with trailing space', function () {
|
||||
it ('trailing space will be trimmed', function () {
|
||||
const uastring = ' Opera/9.21 (Windows NT 5.1; U; ru) ';
|
||||
const { ua } = UAParser(uastring);
|
||||
assert.equal(ua, 'Opera/9.21 (Windows NT 5.1; U; ru) ');
|
||||
});
|
||||
});
|
||||
|
||||
describe('User-agent length', function () {
|
||||
var UA_MAX_LENGTH = 500;
|
||||
|
||||
@@ -382,15 +375,12 @@ describe('Read user-agent data from req.headers', function () {
|
||||
assert.strictEqual(engine.name, "EdgeHTML");
|
||||
});
|
||||
|
||||
// Headers supported in node 18+ - https://developer.mozilla.org/en-US/docs/Web/API/Headers
|
||||
if (typeof Headers !== 'undefined') {
|
||||
it('Fetch API\'s Header can be passed directly into headers', () => {
|
||||
const reqHeaders = new Headers();
|
||||
reqHeaders.append('User-Agent', 'Midori/0.2.2 (X11; Linux i686; U; en-us) WebKit/531.2+');
|
||||
const { browser } = UAParser(reqHeaders);
|
||||
assert.strictEqual(browser.is('Midori'), true);
|
||||
});
|
||||
}
|
||||
|
||||
it('Headers field name should be case insensitive', function () {
|
||||
const hEaDeRs = {
|
||||
|
||||
@@ -1,42 +0,0 @@
|
||||
const assert = require('assert');
|
||||
const { UAParser } = require('../../../src/main/ua-parser');
|
||||
const { isAICrawler, isBot } = require('../../../src/bot-detection/bot-detection');
|
||||
const { Bots, Emails } = require('../../../src/extensions/ua-parser-extensions');
|
||||
|
||||
describe('isAICrawler()', () => {
|
||||
it('Can detect AI Crawlers', () => {
|
||||
|
||||
// AI Crawlers
|
||||
const claudeBot = 'Mozilla/5.0 AppleWebKit/537.36 (KHTML, like Gecko; compatible; ClaudeBot/1.0; +claudebot@anthropic.com)';
|
||||
const searchGPT = 'Mozilla/5.0 AppleWebKit/537.36 (KHTML, like Gecko); compatible; OAI-SearchBot/1.0; +https://openai.com/searchbot';
|
||||
const semrushAI = 'Mozilla/5.0 (compatible; SemrushBot-OCOB/1; +https://www.semrush.com/bot/)';
|
||||
|
||||
assert.equal(isAICrawler(claudeBot), true);
|
||||
assert.equal(isAICrawler(searchGPT), true);
|
||||
assert.equal(isAICrawler(semrushAI), true);
|
||||
|
||||
// Non-AI Crawlers
|
||||
const firefox = 'Mozilla/5.0 (X11; Linux x86_64; rv:109.0) Gecko/20100101 Firefox/111.0';
|
||||
|
||||
assert.equal(isAICrawler(firefox), false);
|
||||
});
|
||||
});
|
||||
|
||||
describe('isBot()', () => {
|
||||
it('Can detect general Bots', () => {
|
||||
|
||||
// Bots
|
||||
const ahrefsBot = 'Mozilla/5.0 (compatible; AhrefsBot/7.0; +http://ahrefs.com/robot/)';
|
||||
const scrapy = 'Scrapy/1.5.0 (+https://scrapy.org)';
|
||||
|
||||
assert.equal(isBot(ahrefsBot), true);
|
||||
assert.equal(isBot(scrapy), true);
|
||||
|
||||
// Non-bots
|
||||
const firefox = 'Mozilla/5.0 (X11; Linux x86_64; rv:109.0) Gecko/20100101 Firefox/111.0';
|
||||
const thunderbird = 'Mozilla/5.0 (X11; Linux x86_64; rv:78.0) Gecko/20100101 Thunderbird/78.13.0';
|
||||
|
||||
assert.equal(isBot(firefox), false);
|
||||
assert.equal(isBot(thunderbird), false);
|
||||
});
|
||||
});
|
||||
@@ -1,16 +0,0 @@
|
||||
const assert = require('assert');
|
||||
const { UAParser } = require('../../../src/main/ua-parser');
|
||||
const { isChromeFamily } = require('../../../src/browser-detection/browser-detection');
|
||||
|
||||
describe('isChromeFamily()', () => {
|
||||
it('Can detect Chromium-based browser', () => {
|
||||
|
||||
const edge = 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/119.0.0.0 Safari/537.36 Edg/119.0.2151.58';
|
||||
const firefox = 'Mozilla/5.0 (X11; Linux x86_64; rv:109.0) Gecko/20100101 Firefox/111.0';
|
||||
|
||||
assert.equal(isChromeFamily(UAParser(edge)), true);
|
||||
assert.equal(isChromeFamily(edge), true);
|
||||
assert.equal(isChromeFamily(UAParser(firefox)), false);
|
||||
assert.equal(isChromeFamily(firefox), false);
|
||||
});
|
||||
});
|
||||
@@ -1,32 +0,0 @@
|
||||
const assert = require('assert');
|
||||
const { UAParser } = require('../../../src/main/ua-parser');
|
||||
const { getDeviceVendor, isAppleSilicon } = require('../../../src/device-detection/device-detection');
|
||||
const { DeviceVendor } = require('../../../src/enums/ua-parser-enums');
|
||||
|
||||
describe('getDeviceVendor()', () => {
|
||||
it('Can guess the device vendor from a model name', () => {
|
||||
|
||||
const sm = 'SM-A605G';
|
||||
const redmi = 'Redmi Note 8';
|
||||
const nexus = 'Nexus 6P';
|
||||
const aquos = 'AQUOS-TVX19B';
|
||||
|
||||
assert.equal(getDeviceVendor(sm), DeviceVendor.SAMSUNG);
|
||||
assert.equal(getDeviceVendor(redmi), DeviceVendor.XIAOMI);
|
||||
assert.equal(getDeviceVendor(nexus), DeviceVendor.HUAWEI);
|
||||
assert.equal(getDeviceVendor(aquos), DeviceVendor.SHARP);
|
||||
});
|
||||
});
|
||||
|
||||
describe('isAppleSilicon()', () => {
|
||||
it('Can detect Apple Silicon device', () => {
|
||||
|
||||
const macARM = 'Mozilla/5.0 (Macintosh; ARM; Mac OS X 10.15; rv:97.0) Gecko/20100101 Firefox/97.0';
|
||||
const macIntel = 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10.15; rv:97.0) Gecko/20100101 Firefox/97.0';
|
||||
|
||||
assert.equal(isAppleSilicon(UAParser(macIntel)), false);
|
||||
assert.equal(isAppleSilicon(macIntel), false);
|
||||
assert.equal(isAppleSilicon(UAParser(macARM)), true);
|
||||
assert.equal(isAppleSilicon(macARM), true);
|
||||
});
|
||||
});
|
||||
@@ -1,13 +0,0 @@
|
||||
const assert = require('assert');
|
||||
const { isFrozenUA } = require('../../../src/helpers/ua-parser-helpers');
|
||||
|
||||
describe('isFrozenUA()', () => {
|
||||
it('matches supplied user-agent string with known frozen user-agent pattern', () => {
|
||||
|
||||
const regularMobileUA = "Mozilla/5.0 (Linux; Android 9; SM-A205U) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/93.0.1234.56 Mobile Safari/537.36";
|
||||
const frozenMobileUA = "Mozilla/5.0 (Linux; Android 10; K) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/93.0.0.0 Mobile Safari/537.36";
|
||||
|
||||
assert.equal(isFrozenUA(regularMobileUA), false);
|
||||
assert.equal(isFrozenUA(frozenMobileUA), true);
|
||||
});
|
||||
});
|
||||
@@ -414,19 +414,3 @@ describe('Identify vendor & type of device from given model name', () => {
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
describe('Chaining withClientHints() & withFeatureCheck() in server-side development', () => {
|
||||
const headers = {
|
||||
'user-agent' : 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/16.0 Safari/605.1.15',
|
||||
'sec-ch-ua-form-factors' : '"VR"'
|
||||
};
|
||||
const device = new UAParser(headers).getDevice();
|
||||
it('Chain order: withFeatureCheck().withClientHints()', () => {
|
||||
const fc2ch = device.withFeatureCheck().withClientHints();
|
||||
assert.strictEqual(fc2ch.type, "xr");
|
||||
});
|
||||
it('Chain order: withClientHints().withFeatureCheck()', () => {
|
||||
const ch2fc = device.withClientHints().withFeatureCheck();
|
||||
assert.strictEqual(ch2fc.type, "xr");
|
||||
});
|
||||
});
|
||||
Reference in New Issue
Block a user