text:
# Contributor Covenant Code of Conduct

## Our Pledge

In the interest of fostering an open and welcoming environment, we as contributors and maintainers pledge to making participation in our project and our community a harassment-free experience for everyone, regardless of age, body size, disability, ethnicity, gender identity and expression, level of experience, nationality, personal appearance, race, religion, or sexual identity and orientation.

## Our Standards

Examples of behavior that contributes to creating a positive environment include:

* Using welcoming and inclusive language
* Being respectful of differing viewpoints and experiences
* Gracefully accepting constructive criticism
* Focusing on what is best for the community
* Showing empathy towards other community members

Examples of unacceptable behavior by participants include:

* The use of sexualized language or imagery and unwelcome sexual attention or advances
* Trolling, insulting/derogatory comments, and personal or political attacks
* Public or private harassment
* Publishing others' private information, such as a physical or electronic address, without explicit permission
* Other conduct which could reasonably be considered inappropriate in a professional setting

## Our Responsibilities

Project maintainers are responsible for clarifying the standards of acceptable behavior and are expected to take appropriate and fair corrective action in response to any instances of unacceptable behavior.

Project maintainers have the right and responsibility to remove, edit, or reject comments, commits, code, wiki edits, issues, and other contributions that are not aligned to this Code of Conduct, or to ban temporarily or permanently any contributor for other behaviors that they deem inappropriate, threatening, offensive, or harmful.

## Scope

This Code of Conduct applies both within project spaces and in public spaces when an individual is representing the project or its community. Examples of representing a project or community include using an official project e-mail address, posting via an official social media account, or acting as an appointed representative at an online or offline event. Representation of a project may be further defined and clarified by project maintainers.

## Enforcement

Instances of abusive, harassing, or otherwise unacceptable behavior may be reported by contacting the project team at kazhnuz@chlore.net. The project team will review and investigate all complaints, and will respond in a way that it deems appropriate to the circumstances. The project team is obligated to maintain confidentiality with regard to the reporter of an incident. Further details of specific enforcement policies may be posted separately.

Project maintainers who do not follow or enforce the Code of Conduct in good faith may face temporary or permanent repercussions as determined by other members of the project's leadership.

## Attribution

This Code of Conduct is adapted from the [Contributor Covenant][homepage], version 1.4, available at [http://contributor-covenant.org/version/1/4][version]

[homepage]: http://contributor-covenant.org
[version]: http://contributor-covenant.org/version/1/4/

repo_name: Kazhnuz/awesome-gnome

mime_type: text/plain


text:
# Contribution Guidelines

Please note that this project is released with a
[Contributor Code of Conduct](code-of-conduct.md). By participating in this
project you agree to abide by its terms.

---

Ensure your pull request adheres to the following guidelines:

- Search previous suggestions before making a new one, as yours may be a duplicate.
- Try to make your pull request as descriptive as possible, especially the title. "Update Readme.md" makes it harder for us to see directly what your pull request is about :)
- Keep descriptions short, simple and to the point.
- End all descriptions with a full stop/period.
- Titles should be [capitalized](http://grammar.yourdictionary.com/capitalization/rules-for-capitalization-in-titles.html).
- Please check your grammar and spelling as much as possible.
- Make sure your text editor is set to remove trailing whitespace.
- New categories or improvements to the existing categorization are welcome.
- Please check that your contribution follows the following requirements :
  - The application has to follow enough of the GNOME HIG to work in a GNOME-based Desktop, by using an headerbar as the titlebar and looking clean in a vanilla GNOME desktop.
  - Please avoid unmaintained items as they could break with time.
  - Please avoid items that haven't had any stable release, aren't mature or aren't mature yet.
  - If the item you propose is a Core GNOME Project, please label it as such.
  - If the item you propose is championned by the [GNOME Circle](https://www.gnome.org/Circle/) initiative, please also label it as such.
- If the item you want to add doesn't follow the requirements for being on this list, but will follow them in the future (in a future version for the HIG, for instance), please submit an issue for it.

Thank you for your suggestions!

## Updating your PR

A lot of times, making a PR adhere to the standards above can be difficult.
If the maintainers notice anything that we'd like changed, we'll ask you to
edit your PR before we merge it. There's no need to open a new PR, just edit
the existing one. If you're not sure how to do that,
[here is a guide](https://github.com/RichardLitt/docs/blob/master/amending-a-commit-guide.md)
on the different ways you can update your PR so that we can merge it.


text:
# Awesome GNOME [![Awesome](https://cdn.rawgit.com/sindresorhus/awesome/d7305f38d29fed78fa85652e3a63e154dd8e8829/media/badge.svg)](https://github.com/sindresorhus/awesome)

[<img src="https://rawgit.com/kazhnuz/awesome-gnome/master/images/gnome-logo.svg" align="right" width="150">](http://www.gnome.org)

> A curated list of _awesome_ apps, extensions, modules, themes and tools for the GNOME Desktop Environment.

[GNOME](https://www.gnome.org/) is a desktop environment for Linux and Unix-like operating systems, designed to put the user in control and get things done. It uses GTK for its applications and Clutter and JavaScript for its official desktop shell.

> Items marked with ![GNOME Core][GNOME Core] are applications officially maintained and distributed by the GNOME Project as part of the core set of applications and tools, or extensions that are maintained and distributed as part of the Classic mode.

> Items marked with ![GNOME Circle][GNOME Circle] are applications championed by the [GNOME Circle](https://circle.gnome.org/) initiative that aims to showcase the best apps and libraries for GNOME.

## Contents

- [Applications](#applications)
  - [Internet and Networking](#internet-and-networking)
  - [Office](#office)
  - [Productivity and Time](#productivity-and-time)
  - [Well Being](#well-being)
  - [Multimedia](#multimedia)
  - [Graphics](#graphics)
  - [Gaming](#gaming)
  - [System and Customization](#system-and-customization)
  - [Utilities](#utilities)
  - [Security and Privacy](#security-and-privacy)
  - [Development and Design](#development-and-design)
  - [Others](#others)
- [Third-party Apps Plugins](#third-party-apps-plugins)
- [Extensions](#extensions)
  - [Docks and Panels](#docks-and-panels)
  - [Customization and Tweaks](#customization-and-tweaks)
  - [Menus](#menus)
  - [Applets](#applets)
  - [Windows](#windows)
  - [Visual Changes](#visual-changes)
  - [Services Integration](#services-integration)
- [Look and Feel](#look-and-feel)
  - [Icons](#icons)
  - [Cursors](#cursors)
- [Community](#community)
- [Developer Resources](#developer-resources)
  - [Libraries](#libraries)
  - [Examples](#examples)
  - [Documentation](#documentations)

---

## Applications

### Internet and Networking

- [GNOME Web](https://apps.gnome.org/app/org.gnome.Epiphany/) - Official web browser project of GNOME. ![GNOME Core][GNOME Core]
- [Fragments](https://apps.gnome.org/app/de.haeckerfelix.Fragments/) - BitTorrent client. ![GNOME Circle][GNOME Circle]
- [Newsflash](https://apps.gnome.org/app/com.gitlab.newsflash/) - RSS feeds reader. ![GNOME Circle][GNOME Circle]
- [Font Downloader](https://apps.gnome.org/app/org.gustavoperedo.FontDownloader/) - Install fonts from online sources. ![GNOME Circle][GNOME Circle]
- [Tangram](https://apps.gnome.org/app/re.sonny.Tangram/) - Browser for your pinned tabs. ![GNOME Circle][GNOME Circle]
- [Polari](https://apps.gnome.org/app/org.gnome.Polari/) - Talk to people on IRC. ![GNOME Circle][GNOME Circle]
- [Wrap](https://apps.gnome.org/app/app.drey.Warp/) - Fast and secure file transfer. ![GNOME Circle][GNOME Circle]
- [Wike](https://apps.gnome.org/app/com.github.hugolabe.Wike/) - Search and read Wikipedia articles. ![GNOME Circle][GNOME Circle]
- [Geary](https://wiki.gnome.org/Apps/Geary) - Modern mail client, created originally by Yorba.
- [Feeds](https://gitlab.gnome.org/World/gfeeds) - An RSS/Atom feed reader.
- [Cawbird](https://ibboard.co.uk/cawbird/) - Twitter client.
- [Haguichi](https://www.haguichi.net/) - Graphical frontend for Hamachi.
- [Parabolic](https://github.com/NickvisionApps/Parabolic) - `yt-dlp` graphical fronted.

### Office

- [Apostrophe](https://apps.gnome.org/app/org.gnome.gitlab.somas.Apostrophe/) - Distraction-free Markdown editor. ![GNOME Circle][GNOME Circle]
- [Citations](https://apps.gnome.org/app/org.gnome.World.Citations/) - Manage your bibliography. ![GNOME Circle][GNOME Circle]
- [NFO Viewer](https://flathub.org/apps/details/io.otsaloma.nfoview) - Simple viewer for NFO files, beating text editors with preset font and encoding settings and clickable hyperlink support.
- [Paperwork](https://gitlab.gnome.org/World/OpenPaperwork/paperwork) - Personal document manager for scanned documents and PDFs.
- [Foliate](https://github.com/johnfactotum/foliate) - Simple and modern eBook reader.
- [Pdftag](https://github.com/arrufat/pdftag) - Simple metadata editor for PDFs.
- [Marker](https://github.com/fabiocolacio/Marker) - Markdown editor with an integrated previewer.
- [Paper Clip](https://github.com/Diego-Ivan/Paper-Clip) - PDF metadata editor.

### Productivity and Time

- [Solanum](https://apps.gnome.org/app/org.gnome.Solanum/) - Balance working time and break time. ![GNOME Circle][GNOME Circle]
- [Khronos](https://apps.gnome.org/app/io.github.lainsce.Khronos/) - Log the time it took to do tasks. ![GNOME Core][GNOME Core]
- [Endeavour](https://flathub.org/apps/details/org.gnome.Todo) - Manage your tasks.
- [GTimeLog](https://github.com/gtimelog/gtimelog) - Simple app for keeping track of time.
- [Gnome Pomodoro](http://gnomepomodoro.org/) - Simple pomodoro timer.
- [Timetrack](https://gitlab.gnome.org/danigm/timetrack) - Time tracker.
- [Teleprompter](https://github.com/Nokse22/teleprompter) - Simple application to read scrolling text from your screen.

### Well Being

- [Blanket](https://apps.gnome.org/app/com.rafaelmardojai.Blanket/) - Listen to different sounds. ![GNOME Circle][GNOME Circle]
- [Health](https://apps.gnome.org/app/dev.Cogitri.Health/) - Health tracking. ![GNOME Circle][GNOME Circle]

### Multimedia

- [Shortwave](https://apps.gnome.org/app/de.haeckerfelix.Shortwave/) - Client for web-based radio. ![GNOME Circle][GNOME Circle]
- [Cozy](https://apps.gnome.org/app/com.github.geigi.cozy/) - Audiobook player. ![GNOME Circle][GNOME Circle]
- [Video Trimer](https://apps.gnome.org/app/org.gnome.gitlab.YaLTeR.VideoTrimmer/) - Trim video quickly. ![GNOME Circle][GNOME Circle]
- [Amberol](https://apps.gnome.org/app/io.bassi.Amberol/) - Plays music, and nothing else. ![GNOME Circle][GNOME Circle]
- [Mousai](https://apps.gnome.org/app/io.github.seadve.Mousai/) - Identify any songs in seconds. ![GNOME Circle][GNOME Circle]
- [Podcasts](https://apps.gnome.org/app/org.gnome.Podcasts/) - Listen to your favourite podcasts. ![GNOME Circle][GNOME Circle]
- [Zap](https://apps.gnome.org/app/fr.romainvigier.zap/) - Play sounds from a soundboard. ![GNOME Circle][GNOME Circle]
- [Vocal](https://github.com/needle-and-thread/vocal) - Powerful, beautiful, and simple podcast client for the modern free desktop.
- [Celluloid](https://github.com/celluloid-player/celluloid) - Simple frontend for mpv.
- [Lollypop](https://gitlab.gnome.org/World/lollypop) - Beautiful music application.
- [Parlatype](http://gkarsay.github.io/parlatype/) - Audio player specialized for transcription.
- [Easy Effects](https://github.com/wwmm/easyeffects) -  Audio effects for PipeWire applications .
- [Pitivi](http://www.pitivi.org/) - Beautiful and powerful video editor.
- [Spot](https://github.com/xou816/spot) - Spotify Client.
- [Clapper](https://github.com/Rafostar/clapper) - Simple and modern media player.
- [Footage](https://gitlab.com/adhami3310/Footage) - Application to trim, flip, rotate and crop individual clips.

### Graphics

- [Curtail](https://flathub.org/apps/details/com.github.huluti.Curtail) - Simple & useful image compressor. ![GNOME Circle][GNOME Circle]
- [Drawing](https://apps.gnome.org/app/com.github.maoschanz.drawing/) - Responsive drawing application. ![GNOME Circle][GNOME Circle]
- [Identity](https://apps.gnome.org/app/org.gnome.gitlab.YaLTeR.Identity/) - Compare image and video. ![GNOME Circle][GNOME Circle]
- [Coulr](https://github.com/Huluti/Coulr) - Convert between RGB and hexadecimal codes for colours.
- [Color Picker](https://gitlab.gnome.org/World/gcolor3/) - Color pickle, working on both X11 and Wayland.
- [GThumb](https://wiki.gnome.org/Apps/Gthumb) - Powerful and advanced application to manage your photos and images.

### Scientific Tooling

- [Plots](https://apps.gnome.org/app/com.github.alexhuntley.Plots/) - Simple graph plotting. ![GNOME Circle][GNOME Circle]

### Gaming

- [Lutris](https://github.com/lutris/lutris) - Open Source gaming platform.
- [GNOME Games](https://wiki.gnome.org/Apps/Games) - Game launcher and an emulation frontend to libretro.
- [Cartridges](https://github.com/kra-mo/cartridges) - Game launcher with Steam, Lutris, Heroic, Bottles and itch library import. ![GNOME Circle][GNOME Circle]

### System and Customization

- [Pika Backup](https://apps.gnome.org/app/org.gnome.World.PikaBackup/) - Simple backups based on borg. ![GNOME Circle][GNOME Circle]
- [Déjà Dup Backups](https://apps.gnome.org/app/org.gnome.DejaDup/) - Simple backups tool. ![GNOME Circle][GNOME Circle]
- [GNOME Tweaks](https://wiki.gnome.org/Apps/Tweaks) - Graphical interface for advanced GNOME settings.
- [Tilix](https://github.com/gnunn1/terminix/) - Tiling terminal emulator.
- [Menulibre](https://smdavis.us/projects/menulibre/) - Manage your applications categories if you use a traditional application menu like Arc or the Application Menu.
- [HydraPaper](https://hydrapaper.gabmus.org/) - Set a different background for each monitor.
- [Dynamic Wallpaper Editor](https://github.com/maoschanz/dynamic-wallpaper-editor) - Utility for editing GNOME's XML wallpapers
- [Dynamic Gnome Wallpapers](https://github.com/manishprivet/dynamic-gnome-wallpapers) - Gallery of MacOS like dynamic wallpapers, and easy scripts to install them
- [GDM Settings](https://gdm-settings.github.io) - A settings app for GDM (GNOME's Login Screen a.k.a GNOME Display Manager).
- [AdwSteamGtk](https://github.com/Foldex/AdwSteamGtk) - [Adwaita for Steam](https://github.com/tkashkin/Adwaita-for-Steam) skin installer.
- [Flatseal](https://github.com/tchx84/Flatseal) - Flatpak permission manager.
- [Mission Center](https://missioncenter.io/) - Monitor your CPU, Memory, Disk, Network and GPU usage

### Utilities

- [Dialect](https://apps.gnome.org/app/app.drey.Dialect/) - Translate text. ![GNOME Circle][GNOME Circle]
- [Markets](https://apps.gnome.org/app/com.bitstower.Markets/) - Keep track of your investments. ![GNOME Circle][GNOME Circle]
- [Audio Sharing](https://apps.gnome.org/app/de.haeckerfelix.AudioSharing/) - Share your computer audio. ![GNOME Circle][GNOME Circle]
- [Boatswain](https://apps.gnome.org/app/com.feaneron.Boatswain/) - Control your Elgato Stream Decks. ![GNOME Circle][GNOME Circle]
- [Decoder](https://apps.gnome.org/app/com.belmoussaoui.Decoder/) - Scan and Generate QR Codes. ![GNOME Circle][GNOME Circle]
- [Junction](https://apps.gnome.org/app/re.sonny.Junction/) - Junction lets you choose the application to open files and links. ![GNOME Circle][GNOME Circle]
- [Kooha](https://apps.gnome.org/app/io.github.seadve.Kooha/) - Elegantly record your screen. ![GNOME Circle][GNOME Circle]
- [Metronome](https://apps.gnome.org/app/com.adrienplazas.Metronome/) - Keep the tempo. ![GNOME Circle][GNOME Circle]
- [GPaste](https://github.com/Keruspe/GPaste) - Clipboard manager (composed of an application and a gnome-shell extension).
- [Catfish](https://launchpad.net/catfish-search) - Simple search application.
- [Detwinner](https://neatdecisions.com/products/detwinner-linux/) - Simple and fast tool for removing duplicate files.
- [Recipes](https://gitlab.gnome.org/GNOME/recipes/) - Cooking application.
- [Sunflower](http://sunflower-fm.org) - Small and highly customizable twin-panel file manager.

### Security and Privacy

- [Obfuscate](https://apps.gnome.org/app/com.belmoussaoui.Obfuscate/) - Censor private information. ![GNOME Circle][GNOME Circle]
- [Metadata Cleaner](https://apps.gnome.org/app/fr.romainvigier.MetadataCleaner/) - View and clean metadata in files. ![GNOME Circle][GNOME Circle]
- [Secrets](https://apps.gnome.org/app/org.gnome.World.Secrets/) - Keepass-compatible password manager. ![GNOME Circle][GNOME Circle]
- [Authenticator](https://apps.gnome.org/app/com.belmoussaoui.Authenticator/) - Generate Two-Factor Codes. ![GNOME Circle][GNOME Circle]
- [Collisions](https://apps.gnome.org/en/app/dev.geopjr.Collision/) - Check hashes for your files. ![GNOME Circle][GNOME Circle]
- [File Shredder](https://apps.gnome.org/app/com.github.ADBeveridge.Raider/) - Securely delete your files. ![GNOME Circle][GNOME Circle]
- [Passbook](https://gitlab.gnome.org/gnumdk/passbook) - Password manager compatible with freedesktop secrets.

### Development and Design

- [GNOME Builder](https://apps.gnome.org/app/org.gnome.Builder/) - Official IDE for creating GNOME applications. ![GNOME Core][GNOME Core]
- [Gaphor](https://gaphor.org) - The simple modeling tool for UML and SysML. ![GNOME Circle][GNOME Circle]
- [Webfont Kit Generator](https://apps.gnome.org/app/com.rafaelmardojai.WebfontKitGenerator/) - Create @font-face kits easily. ![GNOME Circle][GNOME Circle]
- [Commit](https://apps.gnome.org/app/re.sonny.Commit/) - Commit message editor. ![GNOME Circle][GNOME Circle]
- [Workbench](https://apps.gnome.org/app/re.sonny.Workbench/) - Learn and prototype with GNOME technologies. ![GNOME Circle][GNOME Circle]
- [Lorem](https://apps.gnome.org/app/org.gnome.design.Lorem/) - Generate placeholder text. ![GNOME Circle][GNOME Circle]
- [Share Preview](https://apps.gnome.org/app/com.rafaelmardojai.SharePreview/) - Test social media cards locally. ![GNOME Circle][GNOME Circle]
- [Text Pieces](https://apps.gnome.org/app/com.github.liferooter.textpieces/) - Transform text without using random websites. ![GNOME Circle][GNOME Circle]
- [Sysprof](https://apps.gnome.org/app/org.gnome.Sysprof/) - Profile an application or entire system.
- [DevHelp](https://apps.gnome.org/app/org.gnome.Devhelp/) - Developer tool for browsing and searching API documentation.
- [Escambo](https://github.com/CleoMenezesJr/escambo) - HTTP-based APIs test application.

#### Design Tooling

- [App Icon Preview](https://apps.gnome.org/app/org.gnome.design.AppIconPreview/) - Simple utility to preview icons.
- [Palette](https://apps.gnome.org/app/org.gnome.design.Palette/) - Tool for viewing the GNOME colour palette.
- [Contrast](https://apps.gnome.org/app/org.gnome.design.Contrast/) - Check the contrast between two colors.
- [Icon Library](https://apps.gnome.org/app/org.gnome.design.IconLibrary/) - Symbolic icons for your apps.
- [Symbolic Preview](https://apps.gnome.org/app/org.gnome.design.SymbolicPreview/) - Symbolics Made Easy.
- [Emblem](https://apps.gnome.org/app/org.gnome.design.Emblem/) - Generate project avatars.

### Others

- [Boxes](https://apps.gnome.org/en/app/org.gnome.Boxes/) - View, access, and manage remote and virtual systems.

## Third-party Apps Plugins

- [Firefox GNOME Theme](https://github.com/rafaelmardojai/firefox-gnome-theme) - Integrate Firefox into GNOME-based desktop using Adwaita.
- [Nautilus Terminal](https://github.com/flozz/nautilus-terminal) - Integrates a terminal into Nautilus.

## Extensions

### Docks and Panels
- [Dash-to-Dock](https://extensions.gnome.org/extension/307/dash-to-dock/) - A fully-featured dock.
- [Dash-to-Panel](https://extensions.gnome.org/extension/1160/dash-to-panel/) - Make your desktop more similar to W7/KDE.
- [Dock-from-Dash](https://extensions.gnome.org/extension/4703/dock-from-dash/) - Simply transform your Dash into a Dock.

### Customization and Tweaks
- [Just Perfection](https://extensions.gnome.org/extension/3843/just-perfection/) - Customize GNOME Shell.
- [Custom Hot Corners - Extended](https://extensions.gnome.org/extension/4167/custom-hot-corners-extended/) - Customize hot corners.
- [Extensions Sync](https://extensions.gnome.org/extension/1486/extensions-sync/) - Syncs gnome shell keybindings, tweaks settings and extensions with their configuration across all gnome installations.
- [Quick Settings Tweaker](https://extensions.gnome.org/extension/5446/quick-settings-tweaker/) - Tweak your quick settings menu.

### Menus
- [Application Menu](https://extensions.gnome.org/extension/6/applications-menu/) - Category-based menu for applications. ![GNOME Classic][GNOME Core]
- [Places Indicator](https://extensions.gnome.org/extension/8/places-status-indicator/) - Menu that provides fast access to your folders. ![GNOME Classic][GNOME Core]
- [Arc Menu](https://extensions.gnome.org/extension/3628/arcmenu/) - Windows7-like application menu inspired by the one in Zorin OS.
- [Fly-Pie](https://extensions.gnome.org/extension/3433/fly-pie/) - Mouse-based menu.

### Applets
- [RunCat](https://github.com/win0err/gnome-runcat) — The cat tells you the CPU usage by running speed.
- [Caffeine](https://extensions.gnome.org/extension/517/caffeine/) - Applet that let you deactivate the GNOME lock screen.
- [Removable Drive Menu](https://extensions.gnome.org/extension/7/removable-drive-menu/) - Status menu to show your removable drives.
- [OpenWeather](https://extensions.gnome.org/extension/750/openweather/) - Weather applet.
- [Clipboard Indicator](https://extensions.gnome.org/extension/779/clipboard-indicator/) - Simple clipboard applet.
- [Desk Changer](https://extensions.gnome.org/extension/1131/desk-changer/) - Wallpaper slideshow applet.
- [Emoji Selector](https://extensions.gnome.org/extension/1162/emoji-selector/) - Emoji picker applet.
- [Todo.txt](https://extensions.gnome.org/extension/570/todotxt/) - Interface for todo.txt.
- [Time ++](https://extensions.gnome.org/extension/1238/time/) - A todo.txt manager, time tracker, timer, stopwatch, pomodoro, and alarm clock.
- [GSConnect](https://extensions.gnome.org/extension/1319/gsconnect/) - KDE Connect implementation.
- [KStatusNotifiers/AppIndicator Support](https://extensions.gnome.org/extension/615/appindicator-support/) - Appindicator systray.

### Windows
- [PaperWM](https://github.com/paperwm/PaperWM) - Tiled scrollable window management.
- [Coverflow Alt-Tab](https://github.com/dmo60/CoverflowAltTab) - Advanced fullscreen app switcher.

### Audio
- [Application Volume Mixer](https://github.com/mymindstorm/gnome-volume-mixer) - Control volume output per-application.

### Visual Changes
- [Blur-my-shell](https://github.com/aunetx/blur-my-shell) - Apply a blur effect to the overview and top panel background.
- [Transparent Shell](https://github.com/Siroj42/gnome-extension-transparent-shell) - Makes some UI elements transparent.
- [Compiz windows effect](https://extensions.gnome.org/extension/3210/compiz-windows-effect/) - Adds wobbly effects to windows.
- [Useless Gaps](https://extensions.gnome.org/extension/4684/useless-gaps/) - For aesthetic purposes adds useless gaps around tiled and maximized windows.
- [Desktop Cube](https://github.com/Schneegans/Desktop-Cube) - A Desktop Cube for GNOME Shell
- [Burn My Windows](https://github.com/Schneegans/Burn-My-Windows/) - Open/Close your windows with style.

### Services integration
- [GMail Message Tray](https://github.com/shumingch/GmailMessageTray) - Integrate GMail with your desktop.

## Look and Feel

### Icons

#### Upstream Style

- [MoreWaita](https://github.com/somepaulo/MoreWaita) - An Adwaita-style icon theme for Gnome Shell.
- [GNOME++](https://github.com/Bonandry/gnome-plus) - Third-party application icons compatible with GNOME's current guidelines.
- [Pop!](https://github.com/pop-os/icon-theme) - Official icon theme of Pop!\_OS by System76.

#### Material Icons

- [Paper](https://snwh.org/paper) - Material icon theme.
- [Papirus](https://github.com/PapirusDevelopmentTeam/papirus-icon-theme) - Material icon theme, initially based on Paper.

#### Flat Icons

- [La Capitaine](https://github.com/keeferrourke/la-capitaine-icon-theme) - Icon inspired by macOS and Material Design guidelines.

#### Homogeneous Icons

- [Obsidian](https://github.com/madmaxms/iconpack-obsidian/) - Continuation of the famous Faenza theme.
- [Numix Circle](https://github.com/numixproject/numix-icon-theme-circle) - Flat rounded icon theme.
- [Numix Square](https://github.com/numixproject/numix-icon-theme-square) - Flat square icon theme.

#### Skeumorphic Icons

- [Elementary XFCE](https://github.com/shimmerproject/elementary-xfce) - Desktop-agnostic version of the icons of elementary OS.

### Cursors
 - [ComixCursors](https://www.gnome-look.org/p/999996/) - X11 mouse theme with a comics feeling.
 - [Bibata](https://github.com/KaizIqbal/Bibata_Cursor) - Silm material-based cursor theme.
 - [Capitaine Cursors](https://github.com/keeferrourke/capitaine-cursors) - An x-cursor theme inspired by macOS and based on KDE Breeze. Designed to be paired with La Capitaine icons.

## Community

### Official Venues

- [GNOME News Feed](https://www.gnome.org/news/) - Official news posts.
- [This Week in GNOME](https://thisweek.gnome.org/) - Weekly news from project maintainers from the community.
- [Apps for GNOME](https://apps.gnome.org/)
- [Planet GNOME](http://planet.gnome.org/) - Federation of GNOME Developers' blogs.
- [GNOME's Discourse](https://discourse.gnome.org)
- [GNOME Wiki](https://wiki.gnome.org/)
- [`#gnome` on GIMPNet](https://kiwiirc.com/client/irc.gnome.org#gnome) - General-purpose GNOME IRC channel ([complete list of channels](https://wiki.gnome.org/Community/GettingInTouch/IRC))

### GNOME Communities

- [Reddit](https://www.reddit.com/r/gnome)
- [Stack Overflow](http://stackoverflow.com/questions/tagged/gnome)

### GNOME on Social Networks

- [`@gnome` on Twitter](https://twitter.com/gnome)
- [`@gnome` on floss.social](https://floss.social/@gnome)
- [`@GNOMEDesktop` on Facebook](https://www.facebook.com/GNOMEDesktop)
- [`GNOMEDesktop` on Youtube](https://www.youtube.com/user/GNOMEDesktop)
- [`GNOMEDesktop` on Peertube](https://peertube.video/accounts/gnome)

## Developer Resources

### Libraries

- [libadwaita](https://gitlab.gnome.org/GNOME/libadwaita/) - Library that contain official GNOME patterns and widgets (GTK4)
- [libhandy](https://gitlab.gnome.org/GNOME/libhandy) - Building blocks for modern adaptive GNOME apps (GTK3)
- [Relm4](https://relm4.org/) - Building native applications with Rust and GTK4

### Examples

- [Hello](https://gitlab.gnome.org/chergert/hello) - Set of Hello World examples for GNOME/GTK in different languages.

### Documentations

- [GNOME Newcomers Wiki](https://wiki.gnome.org/Newcomers/) - Perfect place to start contributing to GNOME.
- [GNOME Developer Center](https://developer.gnome.org/) - Contains all the official GNOME documentations.
- [GTK Documentation](https://docs.gtk.org) - Official GTK documentation.
- [Valadoc](https://valadoc.org/) - Documentation about Vala.
- [GJS Documentation](https://gjs-docs.gnome.org/) - Documentation for the JavaScript GTK bindings.
- [GJS Guide](https://gjs.guide/) - Guide for GJS.
- [The Python GTK+ 3 Tutorial](https://python-gtk-3-tutorial.readthedocs.io/en/latest/) - Introduction to writing GTK+ 3 applications in Python.

[GNOME Core]: https://cdn.rawgit.com/kazhnuz/awesome-gnome/master/images/gnome-icon-symbolic.svg
[GNOME Circle]: https://cdn.rawgit.com/kazhnuz/awesome-gnome/master/images/gnome-circle.png


text:
# Web dictaphone

> NOTE: This repository is archived and has been moved into the MDN Web Docs dom-examples repository under the [media/web-dictaphone](https://github.com/mdn/dom-examples) folder.

repo_name: mdn/web-dictaphone

repo_language: JavaScript


text:
# Community Participation Guidelines

This repository is governed by Mozilla's code of conduct and etiquette guidelines.
For more details, please read the
[Mozilla Community Participation Guidelines](https://www.mozilla.org/about/governance/policies/participation/).

## How to Report
For more information on how to report violations of the Community Participation Guidelines, please read our '[How to Report](https://www.mozilla.org/about/governance/policies/participation/reporting/)' page.

<!--
## Project Specific Etiquette

In some cases, there will be additional project etiquette i.e.: (https://bugzilla.mozilla.org/page.cgi?id=etiquette.html).
Please update for your project.
-->


text:
<!DOCTYPE html>

    <meta charset="utf-8">
    <meta name="viewport" content="width=device-width">
    <title>Web dictaphone</title>
    <link href="styles/app.css" rel="stylesheet" type="text/css">

Web dictaphone

        <canvas class="visualizer" height="60px"></canvas>

          <button class="record">Record</button>
          <button class="stop">Stop</button>

    ❔
    <input type="checkbox" id="toggle">

Information

Web dictaphone is built using getUserMedia and the MediaRecorder API, which provides an easier way to capture Media streams.

Icon courtesy of Find Icons. Thanks to Sole for the Oscilloscope code!


text:
# Web dictaphone

> NOTE: This repository is archived and has been moved into the MDN Web Docs [`dom-examples` repository](https://github.com/mdn/dom-examples) under the `media/web-dictaphone` folder.


text:
// set up basic variables for app

const record = document.querySelector('.record');
const stop = document.querySelector('.stop');
const soundClips = document.querySelector('.sound-clips');
const canvas = document.querySelector('.visualizer');
const mainSection = document.querySelector('.main-controls');

// disable stop button while not recording

stop.disabled = true;

// visualiser setup - create web audio api context and canvas

let audioCtx;
const canvasCtx = canvas.getContext("2d");

//main block for doing the audio recording

if (navigator.mediaDevices.getUserMedia) {
  console.log('getUserMedia supported.');

  const constraints = { audio: true };
  let chunks = [];

  let onSuccess = function(stream) {
    const mediaRecorder = new MediaRecorder(stream);

    visualize(stream);

    record.onclick = function() {
      mediaRecorder.start();
      console.log(mediaRecorder.state);
      console.log("recorder started");
      record.style.background = "red";

      stop.disabled = false;
      record.disabled = true;
    }

    stop.onclick = function() {
      mediaRecorder.stop();
      console.log(mediaRecorder.state);
      console.log("recorder stopped");
      record.style.background = "";
      record.style.color = "";
      // mediaRecorder.requestData();

      stop.disabled = true;
      record.disabled = false;
    }

    mediaRecorder.onstop = function(e) {
      console.log("data available after MediaRecorder.stop() called.");

      const clipName = prompt('Enter a name for your sound clip?','My unnamed clip');

      const clipContainer = document.createElement('article');
      const clipLabel = document.createElement('p');
      const audio = document.createElement('audio');
      const deleteButton = document.createElement('button');

      clipContainer.classList.add('clip');
      audio.setAttribute('controls', '');
      deleteButton.textContent = 'Delete';
      deleteButton.className = 'delete';

      if(clipName === null) {
        clipLabel.textContent = 'My unnamed clip';
      } else {
        clipLabel.textContent = clipName;
      }

      clipContainer.appendChild(audio);
      clipContainer.appendChild(clipLabel);
      clipContainer.appendChild(deleteButton);
      soundClips.appendChild(clipContainer);

      audio.controls = true;
      const blob = new Blob(chunks, { 'type' : 'audio/ogg; codecs=opus' });
      chunks = [];
      const audioURL = window.URL.createObjectURL(blob);
      audio.src = audioURL;
      console.log("recorder stopped");

      deleteButton.onclick = function(e) {
        let evtTgt = e.target;
        evtTgt.parentNode.parentNode.removeChild(evtTgt.parentNode);
      }

      clipLabel.onclick = function() {
        const existingName = clipLabel.textContent;
        const newClipName = prompt('Enter a new name for your sound clip?');
        if(newClipName === null) {
          clipLabel.textContent = existingName;
        } else {
          clipLabel.textContent = newClipName;
        }
      }
    }

    mediaRecorder.ondataavailable = function(e) {
      chunks.push(e.data);
    }
  }

  let onError = function(err) {
    console.log('The following error occured: ' + err);
  }

  navigator.mediaDevices.getUserMedia(constraints).then(onSuccess, onError);

} else {
   console.log('getUserMedia not supported on your browser!');
}

function visualize(stream) {
  if(!audioCtx) {
    audioCtx = new AudioContext();
  }

  const source = audioCtx.createMediaStreamSource(stream);

  const analyser = audioCtx.createAnalyser();
  analyser.fftSize = 2048;
  const bufferLength = analyser.frequencyBinCount;
  const dataArray = new Uint8Array(bufferLength);

  source.connect(analyser);
  //analyser.connect(audioCtx.destination);

  draw()

  function draw() {
    const WIDTH = canvas.width
    const HEIGHT = canvas.height;

    requestAnimationFrame(draw);

    analyser.getByteTimeDomainData(dataArray);

    canvasCtx.fillStyle = 'rgb(200, 200, 200)';
    canvasCtx.fillRect(0, 0, WIDTH, HEIGHT);

    canvasCtx.lineWidth = 2;
    canvasCtx.strokeStyle = 'rgb(0, 0, 0)';

    canvasCtx.beginPath();

    let sliceWidth = WIDTH * 1.0 / bufferLength;
    let x = 0;

    for(let i = 0; i < bufferLength; i++) {

      let v = dataArray[i] / 128.0;
      let y = v * HEIGHT/2;

      if(i === 0) {
        canvasCtx.moveTo(x, y);
      } else {
        canvasCtx.lineTo(x, y);
      }

      x += sliceWidth;
    }

    canvasCtx.lineTo(canvas.width, canvas.height/2);
    canvasCtx.stroke();

  }
}

window.onresize = function() {
  canvas.width = mainSection.offsetWidth;
}

window.onresize();


text:
* {
  margin: 0;
  padding: 0;
  box-sizing: border-box;
}

html, body {
  height: 100%;
}

body {
  font-family: 'Helvetica Neue', Helvetica, Arial, sans-serif;
  font-size: 0.8rem;
}

.wrapper {
  height: 100%;
  display: flex;
  flex-direction: column;
}

h1, h2 {
  font-size: 2rem;
  text-align: center;
  font-weight: normal;
  padding: 0.5rem 0 0 0;
}

.main-controls {
  padding: 0.5rem 0;
}

canvas {
  display: block;
  margin-bottom: 0.5rem;
}

#buttons {
  display: flex;
  flex-direction: row;
  justify-content: space-between;
}

#buttons button {
  font-size: 1rem;
  padding: 1rem;
  width: calc(50% - 0.25rem);
}

button {
  font-size: 1rem;
  background: #0088cc;
  text-align: center;
  color: white;
  border: none;
  transition: all 0.2s;
  padding: 0.5rem;
}

button:hover, button:focus {
  box-shadow: inset 0px 0px 10px rgba(255, 255, 255, 1);
  background: #0ae;
}

button:active {
  box-shadow: inset 0px 0px 20px rgba(0,0,0,0.5);
  transform: translateY(2px);
}

/* Make the clips use as much space as possible, and
 * also show a scrollbar when there are too many clips to show
 * in the available space */
.sound-clips {
  flex: 1;
  overflow: auto;
}

section, article {
  display: block;
}

.clip {
  padding-bottom: 1rem;
}

audio {
  width: 100%;
  display: block;
  margin: 1rem auto 0.5rem;
}

.clip p {
  display: inline-block;
  font-size: 1rem;
}

.clip button {
  font-size: 1rem;
  float: right;
}

button.delete {
  background: #f00;
  padding: 0.5rem 0.75rem;
  font-size: 0.8rem;
}

/* Checkbox hack to control information box display */

label {
  font-size: 3rem;
  position: absolute;
  top: 2px;
  right: 3px;
  z-index: 5;
  cursor: pointer;
  background-color: black;
  border-radius: 10px;
}

input[type=checkbox] {
   position: absolute;
   top: -100px;
}

aside {
  position: fixed;
  top: 0;
  left: 0;
  width: 100%;
  height: 100%;
  transform: translateX(100%);
  transition: 0.3s all ease-out;
  background-color: #efefef;
  padding: 1rem;
}

aside p {
  font-size: 1.2rem;
  margin: 0.5rem 0;
}

aside a {
  color: #666;
}

/* Toggled State of information box */
input[type=checkbox]:checked ~ aside {
  transform: translateX(0);
}

/* Cursor when clip name is clicked over */

.clip p {
  cursor: pointer;
}

/* Adjustments for wider screens */
@media all and (min-width: 800px) {
  /* Don't take all the space as readability is lost when line length
     goes past a certain size */
  .wrapper {
    width: 90%;
    max-width: 1000px;
    margin: 0 auto;
  }
}


text:
version: 0.1.{build}

branches:
  only:
    - master

image: Visual Studio 2017
platform:
  - x64

cache:
  - node_modules
  - '%APPDATA%\npm-cache'
  - '%USERPROFILE%\.electron'
  - '%USERPROFILE%\AppData\Local\Yarn\cache'

init:
  - git config --global core.autocrlf input

install:
  - ps: Install-Product node 8 x64
  - choco install yarn --ignore-dependencies
  - git reset --hard HEAD
  - yarn
  - node --version

build_script:
  - yarn build

test: off

repo_name: mscststs/BLS

repo_language: Vue


text:
# BLS

> Bilibili Live Superviser

#### 简介

这是一个有界面的B站直播挂机工具

目前已经实现的功能非常多，详情请移步Wiki：[查看 Wiki](https://github.com/mscststs/BLS/wiki)

简要包括：自动签到、任务、宝箱、分享视频、小电视等抽奖、应援团签到、瓜子自动换硬币 等

另外还有：按需回避、自动送礼、网络代理、礼物统计 等

#### 更新日志

- 更新日志见 commit 和 release 记录

#### 安装文件下载(.exe文件)
> 下载最新安装包即可使用，不提供 Linux 和 Mac 版，请自行编译。
- 下载地址：[Github-Releases](https://github.com/mscststs/BLS/releases) (无法下载的可以尝试翻墙后再下载)

  在 0.1.1版本，我添加了增量更新功能，但该功能不够稳定，如果出现异常导致程序出错，请重新在release下载最新安装包。

#### 开发和测试

> 建议使用yarn，yarn的安装方法请 Google 或者 百度。

``` bash
# 安装依赖
yarn install

# 热加载模式进行开发
yarn run dev

# 生成安装包
yarn run build

# 更多 Run Script 可以查看 Package.json 文件

```

---

*本项目使用 Electron 和 Vue.js ，基于 vue-cli 构建。*

-----

### 版权声明

本项目开源但是**保留版权**，使用到的相关开源代码的授权声明见程序 “关于” 页。

本项目的成果，包括代码和发布的二进制程序，允许免费使用，但是不允许进行二次修改并发行。


text:
<!DOCTYPE html>

    <meta charset="utf-8">
    <title>苹朵</title>
    <% if (htmlWebpackPlugin.options.nodeModules) { %>

    <% } %>

          载入中...


text:
import { app, BrowserWindow,Menu,ipcMain } from 'electron'

/**
 * Set `__static` path to static files in production
 * https://simulatedgreg.gitbooks.io/electron-vue/content/en/using-static-assets.html
 */
if (process.env.NODE_ENV !== 'development') {
  global.__static = require('path').join(__dirname, '/static').replace(/\\/g, '\\\\')
}

let mainWindow
const winURL = process.env.NODE_ENV === 'development'
  ? `http://localhost:9080`
  : `file://${__dirname}/index.html`

function createWindow () {
  /**
   * Initial window options
   */
  Menu.setApplicationMenu(null);
  mainWindow = new BrowserWindow({
    height: 700,
    useContentSize: true,
    width: 1200,
    minWidth:850,//最小窗口宽度
    minHeight:400,//最小窗口高度
    fullscreenable:false,//禁止最大化
    webPreferences: {
      nodeIntegration: true
    }
  })
  ipcMain.on("DevTools",()=>{
    mainWindow.webContents.openDevTools ();
  })

  mainWindow.loadURL(winURL)

  mainWindow.on('closed', () => {
    mainWindow = null
  })
}

app.on('ready', createWindow)

app.on('window-all-closed', () => {
  if (process.platform !== 'darwin') {
    app.quit()
  }
})

app.on('activate', () => {
  if (mainWindow === null) {
    createWindow()
  }
})

/**
 * Auto Updater
 *
 * Uncomment the following code below and install `electron-updater` to
 * support auto updating. Code Signing with a valid certificate is required.
 * https://simulatedgreg.gitbooks.io/electron-vue/content/en/using-electron-builder.html#auto-updating
 */

/*
import { autoUpdater } from 'electron-updater'

autoUpdater.on('update-downloaded', () => {
  autoUpdater.quitAndInstall()
})

app.on('ready', () => {
  if (process.env.NODE_ENV === 'production') autoUpdater.checkForUpdates()
})
 */


text:
/**
 * This file is used specifically and only for development. It installs
 * `electron-debug` & `vue-devtools`. There shouldn't be any need to
 *  modify this file, but it can be used to extend your development
 *  environment.
 */

/* eslint-disable */

// Set environment for development
process.env.NODE_ENV = 'development'

// Install `electron-debug` with `devtron`
require('electron-debug')({ showDevTools: true })

// Install `vue-devtools`
require('electron').app.on('ready', () => {
  let installExtension = require('electron-devtools-installer')
  installExtension.default(installExtension.VUEJS_DEVTOOLS)
    .then(() => {})
    .catch(err => {
      console.log('Unable to install `vue-devtools`: \n', err)
    })
})

// Require `main` process to boot app
require('./index')


text:
<template>
  <div id="app">
    <landing-page></landing-page>
  </div>
</template>

<script>
import LandingPage from "@/components/LandingPage";

export default {
  name: "bls",
  components: {
    LandingPage
  }
};
</script>

<style>
/* CSS */
* {
  margin: 0;
  padding: 0;
  user-select: none;
  cursor: default;
}
input,
textarea,
pre {
  user-select: text;
}
#app {
  font-family: "PingFang SC", "Helvetica Neue", sans-serif;
  box-shadow: 0px 1px 2px 0px #ccc inset;
  position: absolute;
  top: 0;
  bottom: 0;
  left: 0;
  right: 0;
}

/* 全局样式覆盖 */
div.el-message {
  pointer-events: none;
  opacity: 0.9;
}
div.el-tabs__content {
  height: calc(100% - 30px);
  overflow-y: auto;
}
div::-webkit-scrollbar {
  width: 8px;
  background-color: transparent;
}

div::-webkit-scrollbar-thumb {
  box-shadow: 0 0 0 1px #fff inset;
  background-color: #aaa;
  border-radius: 20px;
}
</style>


text:
import Vue from 'vue'

import App from './App'
import api from "~/tools/api.js"
import store from "~/tools/store.js"
import events from "~/tools/events.js"

import ElementUI from 'element-ui'
import 'element-ui/lib/theme-chalk/index.css'

if (!process.env.IS_WEB) Vue.use(require('vue-electron'))
Vue.config.productionTip = false

Vue.use(ElementUI)

Vue.prototype.$api = api
Vue.prototype.$eve = events
Vue.prototype.$store = new store(window.localStorage,"bls-config");
//Vue.config.silent = true // Vue 静默

window.main = Vue.prototype;

/* eslint-disable no-new */
new Vue({
  components: { App },
  template: '<App/>'
}).$mount('#app')


text:
<template>
  <div class="main">
    <el-tabs @tab-click="resetIndex" type="border-card" v-bind:value="selected" tab-position="left" style="height:100%">
      <el-tab-pane label="自定义" name="自定义">
        <custom></custom>
      </el-tab-pane>
      <el-tab-pane label="Mock" name="Mock">
        <mock></mock>
      </el-tab-pane>
      <el-tab-pane label="配置中心" name="配置中心">
        <config-center></config-center>
      </el-tab-pane>
      <el-tab-pane label="定时任务" name="定时任务">
        <interval-task></interval-task>
      </el-tab-pane>
      <el-tab-pane label="触发任务" name="触发任务">
        <trigger-task></trigger-task>
      </el-tab-pane>
      <el-tab-pane label="统计中心" name="统计中心">
        <count-center></count-center>
      </el-tab-pane>
      <el-tab-pane label="调度响应" name="调度响应">
        <response-center></response-center>
      </el-tab-pane>
      <el-tab-pane label="小黑屋回避" name="小黑屋回避">
        <blackroom-block></blackroom-block>
      </el-tab-pane>
      <el-tab-pane label="代理设置" name="代理设置">
        <agent-proxy></agent-proxy>
      </el-tab-pane>
<!--       <el-tab-pane label="高并发" name="高并发">
        <high-performance></high-performance>
      </el-tab-pane> -->
      <el-tab-pane label="关于" name="关于">
        <about></about>
      </el-tab-pane>
    </el-tabs>
  </div>
</template>
<script>
/* 功能分块逻辑 */

import About from "@/components/stocks/About"
import Custom from "@/components/stocks/Custom"
import ResponseCenter from "@/components/stocks/ResponseCenter"
import ConfigCenter from "@/components/stocks/ConfigCenter"
import IntervalTask from "@/components/stocks/IntervalTask"
import TriggerTask from "@/components/stocks/TriggerTask"
import Mock from "@/components/stocks/Mock"
import CountCenter from "@/components/stocks/CountCenter"
import BlackroomBlock from "@/components/stocks/BlackroomBlock"
import AgentProxy from "@/components/stocks/AgentProxy"
import HighPerformance from "@/components/stocks/HighPerformance"

export default {
  name:"MultipleStocks",
  data(){
      return {
        stocks : [
          "自定义",
          "Mock",
          "配置中心",
          "定时任务",
          "触发任务",
          "统计中心",
          "调度响应",
          "小黑屋回避",
          "代理设置",
          "高并发",
          "关于",
        ],
        selected:"自定义",
      }
  },
  components:{
    Custom, //自定义
    Mock,//Mock
    ConfigCenter, //配置中心
    IntervalTask, //定时任务
    TriggerTask, //触发任务
    CountCenter, //统计中心
    ResponseCenter, //调度响应
    BlackroomBlock, //小黑屋回避
    AgentProxy, //代理设置
    HighPerformance, //高并发
    About, //关于
  },
  mounted(){
    this.addListener();
  },
  methods:{
    resetIndex(panel){
      /* 此处有一个注意点，Tab组件的value属性并非双向绑定，必须添加tab-click事件为value做重新赋值！ */
      this.selected = panel.name;
      this.$eve.emit("tabChanged",panel.name);
    },
    addListener(){
      this.$eve.on("selectTab",(name)=>{
        if(this.stocks.indexOf(name) >=0 ){
          /* 判断事件是否有效 */
          this.selected = name;
        }else{
          this.$eve.emit("error",`选项卡监听到了一个意外指令 ${name}`);
        }
      });
    }
  },
}
</script>
<style scoped>
.main{
  width:100%;
  height:calc(100% - 55px) ;
  overflow: hidden;
}
</style>


text:
<template>

          <el-form size="mini" :inline="true" class="form" @submit.native.prevent>
            <el-form-item label="直播间">
                    <el-input style="width:85px;padding:0 5px;" v-model="room.roomid" placeholder="房间号" :disabled="room.switch" size="mini"></el-input>
            </el-form-item>
            <el-form-item >
                    <el-switch
                        :disabled="!validateRoom"
                        v-model="room.switch"
                        @change="toggleRoom"
                        active-color="#13ce66"
                        inactive-color="#ff4949">
                    </el-switch>
            </el-form-item>
            <el-form-item v-if="room.switch">
              <el-tag size="small">人气：{{room.onlineNumber}}</el-tag>
            </el-form-item>
            <el-form-item v-else>
              <el-tag type="danger" size="small">未连接</el-tag>
            </el-form-item>
          </el-form>

          <el-switch
            v-model="control.active"
            active-color="#13ce66"
            active-text="活动">
          </el-switch>
          <el-switch
          style="margin-top:5px;"
            v-model="control.chat"
            active-color="#13ce66"
            active-text="弹幕">
          </el-switch>

{{info[0]}}

{{info[1]}}

{{info[2]}}

      <danmaku-multiadds></danmaku-multiadds>

</template>


text:
<template>
<el-container style="height:100%">
  <el-aside width="200px">
    <user-config></user-config>
  </el-aside>
  <el-main style="padding:0;max-width:calc(100% - 200px)">
    <danmaku-config></danmaku-config>
    <multiple-stocks></multiple-stocks>
  </el-main>
</el-container>
</template>

<script>
/* 主界面逻辑 */
import user from "~/tools/user.js";
import UserConfig from "@/components/UserConfig";
import DanmakuConfig from "@/components/DanmakuConfig";
import MultipleStocks from "@/components/MultipleStocks";
import {remote} from "electron"

export default {
  name: "LandingPage",
  data() {
    return {};
  },
  mounted() {
    this.addListener();
  },
  methods: {
    addListener(){
      this.$eve.on("restart",message=>{
        this.restart(message);
      })
      this.$eve.on("success",(message)=>{
        this.$message({
          type:"success",
          message,
        });
      })
      this.$eve.on("warning",(message)=>{
        this.$message({
          type:"warning",
          message,
        });
      })
      this.$eve.on("error",(message)=>{
        this.$message.error(message);
      })
    },
    async restart(message){
      this.$eve.emit("success",message);
      await this.sleep(2000);
      for(let i=5;i>0;i--){
        this.$eve.emit("error",`即将重启，还有${i}秒`);
        await this.sleep(1000);
      }
      remote.app.relaunch();
      remote.app.exit(0);
    },
    sleep(ms){
      return new Promise(resolve=>{
        setTimeout(()=>{resolve(ms)},ms);
      });
    }
  },
  components: {
    UserConfig,//用户管理
    DanmakuConfig,//弹幕服务器连接管理
    MultipleStocks,//选项卡
  }
};
</script>


text:
<template>

  <el-dialog title="添加用户" :visible.sync="Nuser.FormVisisble">
  <el-form :model="Nuser">
    <el-form-item label="">
      <el-alert type="warning" title="请确保密码正确，错误次数过多将引发验证码策略"></el-alert>
    </el-form-item>

    <el-form-item label="登录ID" label-width="120px">
      <el-input v-model="Nuser.id" auto-complete="off"></el-input>
    </el-form-item>
    <el-form-item label="密码" label-width="120px">
      <el-input type="password" v-model="Nuser.password" auto-complete="off"></el-input>
    </el-form-item>
    <el-form-item label="昵称" label-width="120px">
      <el-input v-model="Nuser.name" auto-complete="off"></el-input>
    </el-form-item>
    <el-form-item label="验证码" label-width="120px" v-if="Nuser.captcha">

      <el-input v-model="Nuser.code"></el-input>
    </el-form-item>
  </el-form>

    <el-button @click="Nuser.FormVisisble = false">取 消</el-button>
    <el-button type="primary" @click="addUser()" :loading="Nuser.load">确 定</el-button>

</el-dialog>

<el-row>
  <el-col :span="22" :offset="1" style="padding:5px 0">
    <el-button type="primary" plain size="small" @click="Nuser.FormVisisble= true" icon="el-icon-plus" :loading="Nuser.load">添加新用户</el-button>
  </el-col>
  <el-col :span="22" :offset="1">
    <el-collapse accordion v-if="users.length">
      <el-collapse-item  v-for="user in users" :key="user.id">
        <template slot="title">
          {{user.name}}

        </template>

        <el-button type="primary" icon="edit" plain size="small" @click="updatePassword(user)">修改密码</el-button>
        <el-button type="warning" icon="edit" plain size="small" @click="removeUser(user)">删除</el-button>

      </el-collapse-item>
    </el-collapse>
  </el-col>
</el-row>

</template>


text:
<template>

  <el-container>
    <el-header>

BLS调度平台  v{{version}}

    </el-header>
    <el-main>

用于批量调度账号，进行操作

本项目托管于  mscststs@github/BLS ，如有问题反馈请提交issue.

感谢: 使用了  pandaGao@github 的websocket的相关代码，基于MIT协议

感谢: 使用了  lzghzr@github 的客户端api部分，基于MIT协议

     <el-form style="margin-top:30px;" inline>

       <el-form-item label="">
         <el-button type="primary" @click="donate">捐赠(Alipay)</el-button>
         <el-button type="success" @click="donateWechat">捐赠(WechatPay)</el-button>
       </el-form-item>
       <el-form-item label="">
         <el-button type="primary" plain @click="dev">开发者工具</el-button>
       </el-form-item>
       <el-form-item label="">
         <el-button type="infor" plain @click="checkUpdate" :loading="load" :disabled="load">检查更新</el-button>
       </el-form-item>
     </el-form>
    </el-main>
    <el-footer>

 Powered By MSCSTSTS - All Rights Reserved.

    </el-footer>

    <el-dialog
      :title="nv.title"
      :visible.sync="nv.dialogVisible"
      width="30%">

        该更新支持增量更新
        该更新不支持增量更新
        <el-button size="mini" @click="AutoUpdateUsage">使用说明</el-button>

      {{nv.name}}

      {{d}}

        <el-button @click="nv.dialogVisible = false">取 消</el-button>
        <el-button type="primary" @click="ShowNewVersion">查 看</el-button>
        <el-button type="success" @click="Update(nv.remoteTag)" v-show="nv.allowAutoUpdate">增量更新(beta)</el-button>

    </el-dialog>

  </el-container>

</template>


text:
<template>

    <el-row>
        <el-col :span="24">
            <el-form :model="serverConfig" inline size="small">
                <el-form-item label="端口">
                    <el-input v-model="serverConfig.port" placeholder="" :disabled="serverConfig.open"></el-input>
                </el-form-item>
                <el-form-item label="">
                    <el-switch v-model="serverConfig.open"
                    active-text="开启服务器"
                    inactive-text="关闭服务器"
                    @change="ChangeServerStatus"></el-switch>
                </el-form-item>
                <el-form-item label="" style="float:right">
                    <el-button type="primary" plain @click="ServerUsage()">
                        帮助
                    </el-button>
                </el-form-item>
            </el-form>
        </el-col>
        <el-col :span="24" v-if="serverConfig.open">
            <el-alert type="info" title="" :closable="false">
                你可以通过:  http://[你的IP或域名]:{{serverConfig.port}}/    来随时查看统计中心
            </el-alert>
        </el-col>
        <el-col :span="24" style="padding:3px 3px;">
            <el-form inline>
                <el-form-item label="显示更新时间">
                    <el-switch v-model="lastUpdateSwitch"></el-switch>
                </el-form-item>
            </el-form>
        </el-col>
    </el-row>

        <el-table :data="userGifts" ref="CountTable" :cell-style="{padding:'3px 0'}">
            <el-table-column prop="user" label="用户">

            </el-table-column>
            <el-table-column v-for="tp in types" :key="tp" :prop="tp" :label="tp">

                <template slot-scope="scope">
                    {{scope.row[tp]}}
                    {{getUpdateTime(scope.row,tp)}}
                </template>
            </el-table-column>
        </el-table>

</template>


text:
<template>

      <el-collapse>
        <el-collapse-item name="每日签到" title="每日签到">
            <el-row :gutter="20">
              <el-col :span="16">
                  <el-tag type="warning">上次运行时间: {{DailySign.LastRun}}</el-tag>
              </el-col>
              <el-col :span="8">
                  <el-button type="success" size="small" @click="BtnClick_Sign">手动执行</el-button>
              </el-col>
            </el-row>
        </el-collapse-item>
        <el-collapse-item name="每日宝箱" title="每日宝箱">
            <el-row :gutter="20">
              <el-col :span="16">
                  <el-tag type="warning">上次运行时间: {{SilverBox.LastRun}}</el-tag>
              </el-col>
              <el-col :span="8">
                  <el-button type="success" size="small" @click="Silver">手动执行</el-button>
              </el-col>
            </el-row>
        </el-collapse-item>

        <el-collapse-item name="银瓜子换硬币" title="银瓜子换硬币">
            <el-row :gutter="20">
              <el-col :span="16">
                  <el-tag type="warning">上次运行时间: {{Silver2Coin.LastRun}}</el-tag>
              </el-col>
              <el-col :span="8">
                  <el-button type="success" size="small" @click="runSilver2Coin">手动执行</el-button>
              </el-col>
            </el-row>
        </el-collapse-item>

        <el-collapse-item name="自动送礼物" title="自动送礼物">
            <el-row :gutter="20">
              <el-col :span="16">
                  <el-tag type="warning">上次运行时间: {{AutoGift.LastRun}}</el-tag>
              </el-col>
              <el-col :span="8">
                  <el-button type="success" size="small" @click="runAutoGift(true)">手动执行</el-button>
              </el-col>
            </el-row>
        </el-collapse-item>

        <el-collapse-item name="批量更新cookies" title="批量更新cookies">
            <el-row :gutter="20">
              <el-col :span="16">
                  <el-tag type="warning">上次运行时间: {{AutoRefreshToken.LastRun}}</el-tag>
              </el-col>
              <el-col :span="8">
                  <el-button type="success" size="small" @click="RefreshToken">手动执行</el-button>
              </el-col>
            </el-row>
        </el-collapse-item>

        <el-collapse-item name="轮询船员房间" title="轮询船员房间">
            <el-row :gutter="20">

              <el-col>
                <el-form inline>
                  <el-form-item label="自定义舰长接口">
                    <el-input size="mini" style="width:300px" v-model="GuardQuery.GuardUrlConfig"></el-input>
                  </el-form-item>
                </el-form>

              </el-col>
              <el-col :span="16">
                  <el-tag type="warning">上次运行时间: {{GuardQuery.LastRun}}</el-tag>
              </el-col>
              <el-col :span="8">
                  <el-button type="success" size="small" @click="getGuardRoom">手动执行</el-button>
              </el-col>
            </el-row>
        </el-collapse-item>

        <el-collapse-item name="保持在线" title="保持在线">
            <el-row :gutter="20">
              <el-col :span="16">
                  <el-tag type="warning">上次运行时间: {{HeartBeat.LastRun}}</el-tag>
              </el-col>
            </el-row>
        </el-collapse-item>
      </el-collapse>

</template>


text:
<template>

    <el-form :model="custom">
      <el-form-item label="选择用户">
        <el-select v-model="custom.selected" collapse-tags multiple placeholder="请选择">
          <el-option
            v-for="user in users"
            :key="user.name"
            :label="user.name"
            :value="user.name"
            :disabled="!user.isLogin">
          </el-option>
        </el-select>
      </el-form-item>
    </el-form>

  <el-collapse accordion>
    <el-collapse-item name="弹幕发送" title="弹幕发送" >
      <el-form :model="danmaku" inline size="small">
        <el-form-item label="直播间号"><el-input v-model="danmaku.roomid" placeholder="直播间号"></el-input></el-form-item>
        <el-form-item label="弹幕内容"><el-input v-model="danmaku.content" placeholder="弹幕内容"></el-input></el-form-item>
        <el-form-item label=""><el-button type="primary" plain @click="DanmakuSend">发送</el-button></el-form-item>
      </el-form>
    </el-collapse-item>
    <el-collapse-item name="获取直播流" title="获取直播流">
      <el-form :model="LiveStream" size="small" inline @submit.native.prevent>
        <el-form-item label="房间号"><el-input v-model="LiveStream.roomid" placeholder="房间号" clearable ></el-input></el-form-item>
        <el-form-item label="">
          <el-button type="primary" plain :disabled="!LiveStream.roomid.length" @click="getLiveStream">获取</el-button>
          </el-form-item>
          <el-form-item label="" v-if="LiveStream.stream.length">
              <el-select placeholder="请选择" v-model="LiveStream.quality" @change="SwitchQuality" style="width:80px;">
                <el-option
                  v-for="(item,index) in LiveStream.allowedQuality"
                  :key="index+1"
                  :label="LiveStream.qualities[item]"
                  :value="LiveStream.qualities[item]">
                </el-option>
              </el-select>
          </el-form-item>
          <el-form-item label="" v-if="LiveStream.stream.length">
              <el-select placeholder="请选择" v-model="LiveStream.selected" @change="copyStream" style="width:100px;margin-left:30px;">
                <el-option
                  v-for="(item,index) in LiveStream.stream"
                  :key="index+1"
                  :label="'线路'+(index+1)"
                  :value="index+1">
                </el-option>
              </el-select>
          </el-form-item >
          <el-tag  v-if="LiveStream.stream.length" type="success">{{LiveStream.qualities[LiveStream.nowQuality]}}</el-tag>
      </el-form>
    </el-collapse-item>
    <el-collapse-item name="获取cookies" title="获取cookies">
      <el-button type="primary" plain size="small" @click="getUserCookies">复制到剪贴板</el-button>
    </el-collapse-item>
    <el-collapse-item name="总督" title="总督亲密度领取(所有用户)">
      <el-form inline size="small" :model="guardGift" @submit.native.prevent>
        <el-form-item label="房间号">
          <el-input placeholder="房间号1;房间号2..." v-model="guardGift.roomid"></el-input>
        </el-form-item>
        <el-form-item>
          <el-button type="primary" plain size="small" @click="getGuardGift" :disabled="!guardGift.roomid.length">领取亲密度</el-button>
        </el-form-item>
      </el-form>

    </el-collapse-item>
    <el-collapse-item name="主站任务" title="主站分享视频">
      <el-form inline size="small" :model="mainSiteTask" @submit.native.prevent>
        <el-form-item label="AV号">
          <el-input placeholder="7" v-model="mainSiteTask.av" type="number"></el-input>
        </el-form-item>
        <el-form-item>
          <el-button type="primary" plain size="small" @click="watchAndShareAv" :disabled="true">分享(功能已下线)</el-button>
        </el-form-item>
      </el-form>

    </el-collapse-item>
  </el-collapse>

</template>


text:
<template>

        <el-row :gutter="20">
          <el-col :span="24">
              <el-form :model="form" inline>
                <el-form-item label="禁止时间段">
                      <el-time-picker
                        is-range
                        arrow-control
                        v-model="form.time"
                        range-separator="至"
                        start-placeholder="开始时间"
                        end-placeholder="结束时间"
                        placeholder="选择时间范围">
                    </el-time-picker>
                    <el-button type="success" @click="BlockTime">回避该时段</el-button>
                </el-form-item>
              </el-form>
          </el-col>
          <el-col :span="24" style="margin-bottom:14px;">

                  {{time.desc}} <el-button type="primary" plain size="small" @click="RemoveTimeBlock(time)"> X </el-button>

          </el-col>
          <el-col :span="24">
              <el-form :model="form" inline>
                <el-form-item label="小电视回避">
                    <el-switch v-model="form.smalltv" @change="BlackEventChange"></el-switch>
                </el-form-item>
                <el-form-item label="活动抽奖回避">
                    <el-switch v-model="form.raffle" @change="BlackEventChange"></el-switch>
                </el-form-item>
                <el-form-item label="心跳和亲密度回避">
                    <el-switch v-model="form.online" @change="BlackEventChange"></el-switch>
                </el-form-item>
              </el-form>
          </el-col>
          <el-col :span="24" style="margin-top:24px">

          </el-col>
        </el-row>

</template>


text:
<template>

        <el-row :gutter="20">
            <el-col :span="24">
                <el-alert type="warning" title="" :closable="false">高并发 与 代理设置 不推荐同时使用</el-alert>
            </el-col>
            <el-col :span="4" style="margin-top:10px;" v-show="!control.init">
                <el-button type="primary" size="small" @click="initDNSList" plain>初始化</el-button>
            </el-col>
            <el-col :span="20" style="margin-top:10px;" v-show="!control.init">
                <el-alert type="info" title="" :closable="false">首先需要初始化可用DNS列表</el-alert>
            </el-col>
            <el-col :span="24" v-show="control.init">

                    <el-row>
                        <el-col :span="12">
                            <el-switch v-model="control.HighPerformance"
                            active-text="开启高并发模式"></el-switch>
                        </el-col>
                        <el-col :span="12">
                            <el-switch v-model="control.HackAPI"
                            active-text="开启小黑屋穿透"></el-switch>
                        </el-col>
                    </el-row>

            </el-col>
            <el-col :span="24">

            </el-col>
        </el-row>

</template>


text:
<template>

        <el-table :data="config" stripe style="width:100%;" :cell-style='{padding:"4px 0"}'>
          <el-table-column
                prop="name"
                label="昵称"
                fixed
                >
            </el-table-column>
            <el-table-column label="每日签到">
                <template slot-scope="scope">
                    <el-switch v-model="scope.row.DailySign" @change="HandleChanged"></el-switch>
                </template>
            </el-table-column>

            <el-table-column label="换硬币">
                <template slot-scope="scope">
                    <el-switch v-model="scope.row.Silver2Coin" @change="HandleChanged"></el-switch>
                </template>
            </el-table-column>
            <el-table-column label="送礼物 (默认养勋章)" width="180px">
                <template slot-scope="scope">

                        <el-switch class="flex-none padding-sm" v-model="scope.row.AutoGift" @change="HandleChanged"></el-switch>

                        <room-config
                            :userName="scope.row.name"
                            class="flex-auto padding-sm"
                            size="mini"
                            v-show="scope.row.AutoGift"
                            placeholder="自定义房间"
                            v-model="scope.row.AutoGiftTargetRoom"
                            @change="HandleChanged"
                        >
                        </room-config>

                </template>
            </el-table-column>

            <el-table-column label="小电视">
                <template slot-scope="scope">
                    <el-switch v-model="scope.row.SmallTv" @change="HandleChanged"></el-switch>
                </template>
            </el-table-column>
            <el-table-column label="高能抽奖">
                <template slot-scope="scope">
                    <el-switch v-model="scope.row.Raffle" @change="HandleChanged"></el-switch>
                </template>
            </el-table-column>

            <el-table-column label="船员亲密">
                <template slot-scope="scope">
                    <el-switch v-model="scope.row.Guard" @change="HandleChanged"></el-switch>
                </template>
            </el-table-column>
        </el-table>

</template>


text:
<template>
  <div class="Mock">
      <el-row :gutter="10">
        <el-col :span="24">
            <el-form :model="raw" label-width="100px" label-position="left" size="small">
              <el-form-item label="URL">
                  <el-input v-model="raw.uri" placeholder="">
                      <template slot="prepend">https://</template>
                  </el-input>
              </el-form-item>
              <el-form-item label="请求方式">
                  <el-switch v-model="raw.method"
                  active-value="post"
                  inactive-value="get"
                  active-text="POST"
                  inactive-text="GET"
                  active-color="#13ce66"
                  inactive-color="#449cd6"></el-switch>
              </el-form-item>
              <el-form-item label="GET参数">
                  <el-input v-model="raw.data_get" placeholder='{"key1":"value1","key2":"value2"}'></el-input>
              </el-form-item>
              <el-form-item label="POST参数">
                  <el-input :disabled="raw.method=='get'" v-model="raw.data_post" placeholder='{"key1":"value1","key2":"value2"}'></el-input>
              </el-form-item>
              <el-form-item label="认证模式">
                  <el-switch v-model="raw.AppSign" disabled
                  active-text="Token模式"
                  inactive-text="Cookies模式"
                  active-color="#13ce66"
                  inactive-color="#449cd6"></el-switch>
              </el-form-item>
              <el-form-item label="开始">
                  <el-button type="primary" plain :disabled="inprogress" @click="genarate">Genarate</el-button>
              </el-form-item>
            </el-form>
        </el-col>
        <el-col :span="24">
            <el-alert type="info"  v-for="res in aResult" :key="res.user" :title="res.user" style="margin:2px 0;" :closable="false">{{res.result}}</el-alert>
        </el-col>
      </el-row>
  </div>
</template>

<script>
/* 用于自行Mock特殊请求 */
export default {
    name:"Mock",
    data(){
        return{
            raw:{
                uri:"",
                method:"",
                data_get:"",
                data_post:"",
                AppSign:false,
            },
            inprogress:false, //判断当前是否正在发送请求中,
            aResult:[],
        }
    },
    mounted(){

    },
    methods:{
        rawConfirm(){
            if(this.raw.uri.length===0){
                return false;
            }
            try{
                if(this.raw.data_get.length){
                    let s = JSON.parse(this.raw.data_get);
                    if(typeof(s)!="object"){
                        return false;
                    }
                }
                if(this.raw.data_post.length){
                    let s = JSON.parse(this.raw.data_post);
                    if(typeof(s)!="object"){
                        return false;
                    }
                }
            }catch(e){
                return false;
            }
            return true;
        },
        async genarate(){
            if(this.inprogress){
                this.$eve.emit("error","当前已经有一个进程");
                return;
            }
            if(this.rawConfirm()){
                // this.$eve.emit("success","校验成功");
                this.inprogress = true;
                await this.Mock();
                this.inprogress = false;
            }else{
                this.$eve.emit("error","校验失败");
            }
        },
        async fetch(options,user,isAppSign){
            if(isAppSign){ //处理token
                let qs = options.qs;
                qs["access_key"] =user.token.access_token;
                options.qs = user.SignWithBasicQuery(qs);
            }
            let s = await this.$api.use(user).origin(options);
            try{
                s = JSON.parse(s);
            }catch(e){

            }
            let res = {
                user:user.name,
                result:s,
            };
            return res;
        },
        async Mock(){
            let uri  ="https://"+this.raw.uri;
            let method = this.raw.method;
            let qs = {};
            if(this.raw.data_get.length){
                qs = JSON.parse(this.raw.data_get);
            }

            let form= {};
            if(method === "post" && this.raw.data_post.length){
                form = JSON.parse(this.raw.data_post)
            };
            let options = {
                uri,
                method,
                qs,
                form,
            }
            // console.log("emmmmmmmmm")
            let aRequest = [];
            for(let user of this.$store.users){
                if(user.isLogin){
                    aRequest.push(this.fetch(options,user,this.raw.AppSign));
                }
            }

            try{
                this.aResult = await Promise.all(aRequest);
            }catch(e){

            }
        }

    },
}
</script>
<style scoped>

</style>


text:
<template>

      <el-row :gutter="10">
        <el-col :span="24" style="margin-bottom:10px;">
          <el-alert type="warning" title="【警告】" :closable="false">此处的日志将触发界面重绘，非常影响性能，建议使用开发者工具</el-alert>
        </el-col>
        <el-col :span="8">
            <el-checkbox label="错误" border size="small" v-model="control.error"></el-checkbox>
            <el-checkbox label="成功" border size="small" v-model="control.success"></el-checkbox>
            <el-checkbox label="信息" border size="small" v-model="control.info"></el-checkbox>
        </el-col>
        <el-col :span="8">
          <el-switch v-model="allowLog" active-text="允许日志"></el-switch>
        </el-col>
        <el-col :span="4">
            <el-button type="primary" size="mini" plain @click="clear">清空</el-button>
        </el-col>
        <el-col :span="4">
            <el-tag type="warning" size="medium">日志数量:{{msg.length}}</el-tag>
        </el-col>
        <el-col :span="24">

            <el-alert
            v-for="m in filteredMsg"
            :key="m.msg+m.time+Math.random()"
            :type="m.type"
            :title="m.time"
            :closable="false"
            > {{m.msg}}</el-alert>

        </el-col>
      </el-row>

</template>


text:
<template>

        <el-row :gutter="20">
            <el-col :span="24">
                <el-form :model="Settings" >
                    <el-form-item label="代理" label-width="50px">
                        <el-input v-model="Settings.ProxyString" placeholder=" http://localhost:1080  详细分类见下表"></el-input>
                    </el-form-item>
                    <el-form-item label="类型" label-width="50px">
                        <el-switch v-model="Settings.Global"
                        active-text="全局代理" :disabled="Settings.connect">
                        </el-switch>
                        <el-tag type="warning">启用全局代理后将会代理所有的HTTP(s)请求,否则仅代理用户的请求</el-tag>
                    </el-form-item>
                    <el-form-item label="连接" label-width="50px">
                        <el-switch v-model="Settings.connect" @change="Changestatus"></el-switch>

                            {{detail.country}} {{detail.province}} {{detail.city}} {{detail.isp}}

                    </el-form-item>
                </el-form>
            </el-col>
            <el-col :span="24" style="margin-top:20px">

                        配置样例

                            Protocol
                            Example

                            http
                            http://proxy-server-over-tcp.com:3128

                            https
                            https://proxy-server-over-tls.com:3129

                            socks(v5)
                            socks://username:password@some-socks-proxy.com:9050 (username & password 是可选的)

                            socks5
                            socks5://username:password@some-socks-proxy.com:9050 (username & password 是可选的)

                            socks4
                            socks4://some-socks-proxy.com:9050

                            pac
                            pac+http://www.example.com/proxy.pac

            </el-col>
            <el-col :span="24" style="margin-top:10px;">

                    该代理设置不能替代 SS(ShadowSocks)、SSR 等应用层代理软件，需要先使用SS客户端启动本地代理才能使用;

SS的本地代理和其他类型的代理按照上表填写配置即可.

            </el-col>
        </el-row>

</template>


text:
<template>
    <div class="trigger-task">
        <el-collapse>
          <el-collapse-item name="小电视" title="小电视">
              <el-row>
                <el-col :span="6">
                    <el-tag type="success">最近轮次: {{SmallTv.SmallTv_id}}</el-tag>
                </el-col>
                <el-col :span="6">
                    <el-tag type="success">最近房间: {{SmallTv.roomid}}</el-tag>
                </el-col>
                <el-col :span="12">
                </el-col>
              </el-row>
          </el-collapse-item>
          <el-collapse-item name="高能" title="高能">
              <el-row>
                <el-col :span="6">
                    <el-tag type="warning">最近轮次: {{Raffle.Raffle_id}}</el-tag>
                </el-col>
                <el-col :span="6">
                    <el-tag type="warning">最近房间: {{Raffle.roomid}}</el-tag>
                </el-col>
              </el-row>
          </el-collapse-item>
        </el-collapse>
        <el-row :gutter="20" style="margin-top:20px;">
            <el-col :span="4" style="line-height:38px">
              随机丢弃(%)
            </el-col>
            <el-col :span="20">
              <el-slider
                v-model="dispite"
                show-input
                @change="DispiteUpdate">
              </el-slider>
            </el-col>
            <el-col :span="24" style="margin-top:5px;">
              <el-alert type="info" :closable="false" title="">该项用于控制每次抽奖会被随机抛弃的概率</el-alert>
            </el-col>
        </el-row>
    </div>
</template>

<script>
import { setTimeout } from 'timers';
export default {
  name: "TriggerTask",
  data() {
    return {
      SmallTv: {
        roomid: "无",
        SmallTv_id: "无"
      },
      Raffle: {
        roomid: "无",
        Raffle_id: "无"
      },
      indiv:[],
      dispite:5,
    };
  },
  mounted() {
    this.AddListener();
    this.init();
  },
  methods: {
    DispiteUpdate(val){
      this.$store.update(data=>{
        data.LotteryDispite = val;
      });
    },
    init(){
      if(this.$store.data.LotteryDispite||this.$store.data.LotteryDispite===0){
        //当dispite可能等于0时，就不能用if来判断是不是已经定义，需要加上一条
        this.dispite = this.$store.data.LotteryDispite;
      }
    },
    NeedDispite(){
      return Math.round(Math.random()*100) < this.dispite;
    },
    isExsit(str){
      if(this.indiv.indexOf(str)>=0){
        return true;
      }else{
        this.indiv.push(str);
        setTimeout(()=>{
          this.indiv.shift();
        },1000*60*5);//五分钟后移除
        return false;
      }
    },
    AddListener() {
      this.$eve.on("dm_SmallTv", data => {
        // console.log(data);
        this.Checkfish(data, () => {
          this.smalltv(data);
        });

      },-10);
      this.$eve.on("dm_raffle", data => {
        // console.log(data);
        this.Checkfish(data, () => {
          this.appraffle(data);
          this.raffle(data);
        });
      },-10);
      this.$eve.on("dm_liveLottery",data=>{
        this.Checkfish(data,()=>{
          this.lotteryV5(data);
        });
      },-10)
    },
    async Checkfish(data, cb) {
      let roomid = data.roomid;
      let res = await this.$api.send(
        "room/v1/Room/room_init",
        { id: roomid },
        "get"
      );
      if (
        res.code === 0 &&
        !res.data.encrypted &&
        !res.data.is_locked &&
        !res.data.is_hidden
      ) {
        //非钓鱼房间
        let delay = (10+Math.ceil(Math.random()*20))*1000;
        // console.log("延迟 " + delay/1000);
        await this.sleep(delay);//延迟一定时间，据说有用
        // console.log("延迟结束");

        cb();
      } else {
        this.$eve.emit("error", "检测到钓鱼房间！" + roomid);
      }
    },

    async getAppRaffle(event_type,room_id,user){
        try{
            if(this.NeedDispite()){
              this.$eve.emit("info",`${user.name} 丢弃了一个APP 抽奖, 抽奖编号：${raffleId}`);
              return ;
            }
            let join = await this.$api.use(user).send("YunYing/roomEvent",
            user.SignWithBasicQuery({
                event_type,
                room_id,
                access_key:user.token.access_token,
            })
            ,"get");
            if(join.code===0){
                let gift = join.data.gift_desc;
                let giftnum = gift.split("X")[1];
                let giftname = gift.split("X")[0];
                this.$eve.emit("giftCount", user.name, giftname, giftnum,"app抽奖"); //提交统计
            }else{
              this.$eve.emit("info",`${user.name} 参加APP抽奖：${join.msg}`);
            }
        }catch(e){
            this.$eve.emit("info",`${user.name} 参加app 抽奖时: ${e.message}`);
        }
    },
    async getAppRaffleWithRoom(roomid){
        let roominfo=null;
        for(let user of this.$store.users){
            if(user.config.AppRaffle){
                roominfo = await this.$api.use(user).send("AppRoom/index",user.SignWithBasicQuery({
                    room_id:roomid,
                }),"get");
                break;
            }
        }
        if(roominfo){
            for(let ap of roominfo.data.event_corner){
                let type = ap.event_type;
                for(let user of this.$store.users){
                    if(user.config.AppRaffle && user.isLogin){
                        this.getAppRaffle(type,roomid,user); //唤起抽奖
                    }
                }
            }
        }
    },
    appraffle(data){
        // 功能下线 TODO: 转成 cookies 接口
        return;
        let roomid = data.roomid;
        this.getAppRaffleWithRoom(roomid);
    },
    sleep(ms) {
      return new Promise(resolve => setTimeout(resolve, ms));
    },
    async joinRaffle(roomid, raffleId, user) {
      try {
        if(this.NeedDispite()){
          this.$eve.emit("info",`${user.name} 丢弃了一个PC 抽奖, 抽奖编号：${raffleId}`);
          return ;
        }
        let api = this.$api.use(user);
        api.headers["Referer"] = `https://live.bilibili.com/${roomid}`;
        let join = await api.send(
          "activity/v1/Raffle/join",
          { roomid, raffleId },
          "get"
        );
        //console.log(join);
        if (join.code === 0) {
          await this.sleep(180 * 1e3); // 等待三分钟
          let notice = await api.send(
            "activity/v1/Raffle/notice",
            { roomid, raffleId },
            "get"
          );
          if (notice.code === 0) {
            let giftnum = notice.data.gift_num;
            let giftname = notice.data.gift_name;
            this.$eve.emit("giftCount", user.name, giftname, giftnum,"pc抽奖"); //提交统计
          }else{
              this.$eve.emit("info",`${user.name} 获取PC结果：${notice.msg}`);
          }
        }
        else{
              this.$eve.emit("info",`${user.name} 参加PC抽奖：${join.msg}`);
            }
      } catch (e) {
        this.$eve.emit("info", `${user.name} 在参加抽奖时: ${e.message}`);
      }
    },
    async raffle(data) {
      await this.sleep(5000);
      //临时等待5s，防止双端无效

      let roomid = data.real_roomid;
      let rq = await this.$api.send(
        "activity/v1/Raffle/check",
        { roomid },
        "get"
      );
      if (rq.code === 0) {
        for (let rf of rq.data) {
            this.Raffle={
                roomid:data.roomid,
                Raffle_id:rf.raffleId,
            }
          if (rf.status === 1) {
            if(this.isExsit(`pc抽奖${rf.raffleId}`)){
              continue;
            }
            let id = rf.raffleId;
            for (let user of this.$store.users) {
              if (user.config.Raffle && user.isLogin) {
                this.joinRaffle(roomid, id, user);
              }
            }
          }
        }
      }
    },
    async getSmallTv(roomid, raffleId, user,type) {
      try {
        let join = await this.$api
          .use(user)
          .send("gift/v3/smalltv/join", { roomid, raffleId }, "get");
        if (join.code === 0) {
          let Time = join.data.time;
          await this.sleep(Time * 1e3);
          let  FaultRetry=5;
          do{
              await this.sleep(60 * 1e3);
              let notice = await this.$api
                .use(user)
                .send("gift/v3/smalltv/notice", { type, raffleId }, "get");
              if (notice.code === 0 && notice.data.gift_num!=0) {
                let giftnum = notice.data.gift_num;
                let giftname = notice.data.gift_name;
                this.$eve.emit("giftCount", user.name, giftname, giftnum,"小电视抽奖"); //提交统计
                break;
              }else if(notice.code != 0){
                this.$eve.emit("info",`${user.name} 获取小电视结果：${notice.msg}`);
                break;
              }else{
                continue;
              }
            }while(FaultRetry--);
        }else{
              this.$eve.emit("info",`${user.name} 参加小电视抽奖：${join.msg}`);
            }
      } catch (e) {
        this.$eve.emit("info", `${user.name} 参与小电视抽奖时: ${e.message}`);
      }
    },
    async getSmallTv_v4(roomid, raffleId, user,type){
      try{
        let award =await this.$api
          .use(user)
          .origin({
            uri:"http://api.live.bilibili.com/gift/v4/smalltv/getAward",
            form:user.SignWithBasicQuery({
                raffleId,
                roomid,
                type,
              }),
            method:"post",
          });
        if(award.code == -401){
          await this.sleep(20e3);
          this.getSmallTv_v4(roomid, raffleId, user,type)
        }else if(award.code == 0){
          this.$eve.emit("giftCount",user.name,award.data.gift_name,award.data.gift_num,"小电视抽奖");
        }else{
          this.$eve.emit("info",`${user.name} 获取小电视结果：${award.msg}`)
        }
      }catch(e){
        this.$eve.emit("info",`${user.name} 参与小电视抽奖时：${e.message}`);
      }
    },
    async lotteryV5(data){
      let roomid = data.real_roomid;
      let rq = await this.$api.send("xlive/lottery-interface/v1/lottery/Check",{roomid},"get");
      if(rq.code === 0){
        let giftList = rq.data.gift;
        for(let gift of giftList){

          if(this.isExsit(`新抽奖${gift.raffleId}`)){
            continue;
          }
          this.$eve.emit("info",`发现新抽奖, 房间:${roomid},抽奖编号:${gift.raffleId},还有${gift.time_wait}秒开奖`);
          this.$store.users.filter((user)=>{
            return user.config.SmallTv && user.isLogin
          }).forEach((user)=>{
            if(this.NeedDispite()){
              this.$eve.emit("info",`${user.name} 丢弃了一个抽奖, 抽奖编号：${gift.raffleId}`);
            }else{
              this.joinLotteryV5(user,gift.raffleId,roomid,gift.type,gift.time_wait)
            }
          })
        }
      }
    },
    async joinLotteryV5(user,raffleId,roomid,type,time){
      //console.log("触发抽奖",user,raffleId)
      time = time>0?(time+1) : 0;
      await this.sleep(time*1e3)
      try{

        let rq = await this.$api
          .use(user)
          .send("xlive/lottery-interface/v5/smalltv/join",{
            id:raffleId,
            roomid,
            type,
          },"post")
        if(rq.code == 0){

          this.$eve.emit("giftCount",user.name,rq.data.award_name,rq.data.award_num,"抽奖");
          //this.$eve.emit("info",`${user.name} 获取抽奖结果：${rq.data.award_name} X ${rq.data.award_num}`)
        }else{
          this.$eve.emit("info",`${user.name} 参与抽奖时：${rq.msg}`);
        }
      }catch(e){
        this.$eve.emit("info",`${user.name} 参与抽奖时：${e.message}`)
      }

    },
    async smalltv(data) {
      let roomid = data.real_roomid;
      let rq = await this.$api.send("gift/v3/smalltv/check", { roomid }, "get");
      if (rq.code === 0) {
        for (let sm of rq.data.list) {
          this.SmallTv = {
            roomid: data.roomid,
            SmallTv_id: sm.raffleId,
          };
          if (sm.status === 1) {
            if(this.isExsit(`小电视${sm.raffleId}`)){
              continue;
            }
            let id = sm.raffleId;
            let type = sm.type;
            for (let user of this.$store.users) {
              if (user.config.SmallTv && user.isLogin) {
                // console.log(roomid + " " + id);
                if(this.NeedDispite()){
                  //小电视抽奖丢弃提前，防止后面递归出现重复丢弃
                  this.$eve.emit("info",`${user.name} 丢弃了一个小电视抽奖, 抽奖编号：${id}`);
                  continue;
                }

                if(this.SmallTv_Use_V4){
                  //如果使用v4 API
                  this.getSmallTv_v4(roomid, id, user,type);
                }else{
                  this.getSmallTv(roomid, id, user,type);
                }
              }
            }
          }
        }
      }
    }
  }
};
</script>
<style scoped>

</style>


text:
import http from "http"
import eve from "~/tools/events"

class myserver{
    constructor(getCallback){
        this.getRawHTML = getCallback;
        this.server = null;
        this.OauthToken = "";
    }
    getResponse(){
        return `
            <!DOCTYPE html>
            <html>
                <head>
                    <meta charset="utf-8">
                    <link rel="stylesheet" href="https://unpkg.com/element-ui/lib/theme-chalk/index.css">
                    <title>BLS-统计中心</title>
                </head>
                <body>
                    ${this.getRawHTML()}
                </body>
            </html>
        `;
    }
    async Open(port){
        try{
            this.server = http.createServer((req,res)=>{
                res.writeHead(200,{"Content-type":"text/html"});
                res.write(this.getResponse());
                res.end();
            });
            this.server.listen(port);
            return true;
        }catch(e){
            eve.emit("error",`创建HTTP服务时出错：${e.message}`);
            return false;
        }
    }
    close(){
        this.server.close();
    }
}

export default myserver;


text:
<template>

        <el-input
            :placeholder="placeholder"
            :size="size"
            :value="formValue"
            readonly
            @focus="showDialog"
            ref="formInput">
        </el-input>
        <el-dialog title="送礼优先级配置"
        width="90vw"
            :close-on-click-modal="false"
            :visible.sync="dialogVisible">

                第一优先级:
                <el-tag
                        v-for="medal in step1_medals"
                        :key="medal.roomid"
                        size="mini"
                        type=""
                        effect="dark"
                        :hit="false"
                        :style="{color:'#ffffff','marginRight':'3px'}"
                        :color="'#'+(medal.color).toString(16)"
                    >{{medal.medal_name}}</el-tag>

                第二优先级:
                <el-tag
                        v-for="medal in step2_medals"
                        :key="medal.roomid"
                        size="mini"
                        type=""
                        effect="dark"
                        :hit="false"
                        :style="{color:'#ffffff','marginRight':'3px'}"
                        :color="'#'+(medal.color).toString(16)"
                    >{{medal.medal_name}}</el-tag>

                第三优先级:
                <el-input
                style="width:50%;"
                v-model="form.step3"
                size="mini"
                placeholder="一个房间号，该房间用于处理所有未用完的一天内辣条">

                </el-input>

            <el-table ref="table" :data="fansMedalList"  :cell-style='{padding:"1px 0"}' style="width:100%;"
            >
                <el-table-column label="勋章名称" >
                <template slot-scope="scope">
                    <el-tag
                        size="mini"
                        type=""
                        effect="dark"
                        :hit="false"
                        :style="{color:'#ffffff'}"
                        :color="'#'+(scope.row.color).toString(16)"
                    >{{scope.row.medal_name}}</el-tag>
                </template>
                </el-table-column>
                <el-table-column
                    prop="level"
                    label="等级"
                ></el-table-column>
                <el-table-column label="今日上限">
                    <template slot-scope="scope">

                            {{scope.row.today_feed}}/{{scope.row.dayLimit}}

                    </template>
                </el-table-column>
                <el-table-column label="升级进度">
                    <template slot-scope="scope">

                            {{scope.row.intimacy}}/{{scope.row.next_intimacy}}

                    </template>
                </el-table-column>
                <el-table-column label="第一优先级">
                    <template slot-scope="scope" v-if="!~form.step2.indexOf(scope.row.roomid)">
                        <el-button
                            v-if="!~form.step1.indexOf(scope.row.roomid)"
                            type="primary"
                            size="mini"
                            @click="push(scope.row,'step1')">
                            添加
                        </el-button>
                        <el-button
                            v-else
                            type="danger"
                            size="mini"
                            @click="remove(scope.row,'step1')"
                            >
                            移除
                        </el-button>
                    </template>
                </el-table-column>
                <el-table-column label="第二优先级">
                    <template slot-scope="scope" v-if="!~form.step1.indexOf(scope.row.roomid)">
                        <el-button
                            v-if="!~form.step2.indexOf(scope.row.roomid)"
                            type="primary"
                            size="mini"
                            @click="push(scope.row,'step2')">
                            添加
                        </el-button>
                        <el-button
                            v-else
                            type="danger"
                            size="mini"
                            @click="remove(scope.row,'step2')"
                            >
                            移除
                        </el-button>
                    </template>
                </el-table-column>
            </el-table>

            <el-row style="margin-top:20px">
                <el-col :span="24">
                    <el-button type="primary" size="mini" @click="save">保存</el-button>
                    <el-button type="danger" size="mini" @click="()=>{dialogVisible=false}">取消</el-button>
                </el-col>
            </el-row>
        </el-dialog>

</template>


text:
<template>

                {{s.name}}<el-switch v-model="s.dm.allow" style="margin:-5px 5px 0px 5px;"></el-switch>

                {{s.dm.roomid}}{{s.dm.allow?s.dm.status?"已连接":"已断开":"不监听"}}

</template>


text:
import DmService from "~/tools/danmaku";
import api from "~/tools/api";
import eve from  "~/tools/events"

class dm {
    constructor(type,name) {
        this.name = name;
        this.type = type;
        this.status = false;
        this.roomid = 0;
        this.dm = {};
        this.allow = true;
        this._initConnect = false; //用于首次初始化的时候过滤HeartBeat的消息。
        eve.on("HeartBeat",()=>{
            if(this._initConnect){
                if(this.status){
                    this.CheckInType();
                }else{
                    //status 变成断开，需要重新连接

                    this.roomid = 0;
                    this.CheckInType();
                }
            }
        })
    }
    async CheckInType(){
        let flag = false;
        let rq = await api.send("room/v1/area/getRoomList", {
            platform: "web",
            parent_area_id: this.type,
            sort_type: "online",
            page_size: "30",
        }, "get");

        //检查签前30热度的是否还有该主播

        for(let r of rq.data){
            if(r.roomid==this.roomid){
                flag = true;
            }
        }

        if(!flag){
            eve.emit("info",this.name + "分区检测 ：检测到房间分区/房间热度变化，自动重新选择房间");
            this.disconnect();
            this.connect();
        }else{
            //eve.emit("info",this.name + "分区检测 ：房间分区正常");
            //无须打印这么多正常房间消息
        }
    }
    async connect() {
        if (Object.keys(this.dm).length && this.dm._socket) {
            /* 防止多个socket并存 */
            this.disconnect();
        }

        let roomid = await this.getOnlineRoom();
        if(roomid!=0){
            this.roomid = roomid;
            this.dm = new DmService({
                roomId: roomid
            });
            this.dm.on("connected", () => {
                this.status = true;
                eve.emit("success", `${this.name}分区： 直播间 ${roomid} 连接成功`);
            });
            this.dm.connect();
            this.dm.on("data", data => {
                // console.log(data);
                switch (data.type) {
                    case 'NOTICE_MSG':
                        if(data.msg_self.indexOf("全区")<0 &&data.msg_self.indexOf("抽奖")>=0){
                            //单区广播礼物
                            eve.emit("dm_liveLottery",data)
                        }
                        break;
                    case "comment":
                        break;
                    case "SYS_MSG":
                        /* 绘马没有roomid参数，小电视+摩天大楼等绿色通知 */
                        if (data.roomid) {
                            if (data.msg.indexOf("摩天大楼")>=0) {
                                //仅提取摩天大楼
                                if(this.allow){
                                    eve.emit("dm_SmallTv", data);
                                }
                            }
                            //console.log(data);
                        }
                        break;
                    case "SYS_GIFT":

                        break;
                    case "online":
                        if(data.type!="online"||data.number<=10){
                            //number为0时即为下播
                            this.disconnect();
                            this.connect();
                            //当直播下线时自动切换到其他主播
                            eve.emit("info",`${this.name}分区： 检测到下播，自动切换其他房间 ...`);
                        }
                        //console.log(data);
                        break;
                    case "gift":
                        break;
                    case "ROOM_SILENT_OFF":
                        this.disconnect();
                        this.connect();
                        //当直播下线时自动切换到其他主播
                        eve.emit("info",`${this.name}分区： 检测到下播，自动切换其他房间 ...`);
                        break;
                    default:
                        break;
                }
            });
        }

        this._initConnect = true; //设置initConnect的值，用于监听器判断当前是正在工作中状态
    }
    disconnect() {
        this.status = false;
        if(typeof this.dm.disconnect =="function"){
            this.dm.disconnect();
        }
        this.dm = {};
    }
    async getOnlineRoom(retry = 0) {
        let roomid ;
        try{
            let rq = await api.send("room/v1/area/getRoomList", {
                platform: "web",
                parent_area_id: this.type,
                sort_type: "online",
                page_size: "30",
            }, "get");
            let rooms =[];
            for(let r of rq.data){
                if(r.roomid==this.roomid){
                }else{
                    rooms.push(r);
                }
                 //取出非当前直播间的另一个直播间（热度更新有延迟）
            }
            if(rooms.length == 0){
                // fix 此处用于解决一个奇怪的undifined问题
                throw new Error("可用房间数量为 0 ");
            }else{
                rooms.sort((a, b) => { return b.online - a.online });
                roomid = rooms[ Math.floor((Math.random()/2*rooms.length))].roomid; //随机取一个房间
            }
        }
        catch(e){
            eve.emit("info",`${this.name} :获取直播房间：${e.message}`);
            if(retry>=5){
                roomid = 0;
            }else{
                eve.emit("info",`获取房间列表出错，第${retry+1}次尝试`);
                roomid = await this.getOnlineRoom(retry+1);
            }

        }
        finally{
            return roomid;
        }

    }
}
export default dm;