Pastebin -> sub migrated
!pastebin
help-circle
rss

3

Process file text with coqui-ai TTS
``` package main import ( "log" "os" "os/exec" "strconv" "github.com/cheggaaa/pb/v3" "github.com/neurosnap/sentences/english" ) func main() { if len(os.Args) != 2 { log.Fatalf("Usage: go run main.go <input>") } sentences := get_sentences() audio_files := convert_text_to_audio(sentences) concatenate_audio_files(audio_files) } func get_sentences() []string { tokenizer, err := english.NewSentenceTokenizer(nil) if err != nil { panic(err) } text, err := os.ReadFile(os.Args[1]) if err != nil { log.Fatal(err) } tmp := tokenizer.Tokenize(string(text)) var sentences []string for _, sentence := range tmp { sentences = append(sentences, sentence.Text) } return sentences } func convert_text_to_audio(sentences []string) []string { var audio_files []string bar := pb.StartNew(len(sentences)) for i, sentence := range sentences { audio_file := "out_" + strconv.Itoa(i) + ".wav" cmd := exec.Command("tts", "--text", sentence, "--model_name", "tts_models/en/ljspeech/tacotron2-DDC", "--out_path", audio_file) err := cmd.Run() if err != nil { log.Println(cmd.String()) log.Println("Failed to run coqui-ai tts") } else { audio_files = append(audio_files, audio_file) } bar.Increment() } bar.Finish() return audio_files } func concatenate_audio_files(audio_files []string) { audio_files = append(audio_files, "out.wav") cmd := exec.Command("sox", audio_files...) err := cmd.Run() if err != nil { log.Fatalf("Failed to run sox") } } ```

Async web scraper
``` import asyncio from aiohttp_scraper import Proxies from aiohttp_scraper import ScraperSession as ClientSession from urllib.request import urlopen def scrape(): TEST_URL = "https://books.toscrape.com/catalogue/" urls = [f"{TEST_URL}page-{str(i)}.html" for i in range(1, 5)] scraper = WebScraper(urls) asyncio.run(scraper.run()) print(scraper.master_dict) def get_proxies() -> Proxies: PROXY_URL = "https://raw.githubusercontent.com/TheSpeedX/SOCKS-List/master/http.txt" proxies = urlopen(PROXY_URL).read().decode('utf-8').splitlines() return Proxies( proxies=proxies, redis_uri="redis://localhost:6379", window_size_in_minutes=5, max_requests_per_window=300, ) class WebScraper(object): def __init__(self, urls): self.urls = urls self.proxies = get_proxies() self.master_dict = {} async def run(self): loop = asyncio.get_event_loop() async with ClientSession(loop=loop) as session: tasks = [loop.create_task(self.fetch(session, url)) for url in self.urls] await asyncio.gather(*tasks) async def fetch(self, session, url): async with session.get(url) as response: print(response.status) self.master_dict[url] = await response.text() if __name__ == "__main__": scrape() ```

Asynchronous Web Scraping In Python
https://understandingdata.com/python-for-seo/asynchronous-web-scraping-python/ ``` class WebScraper(object): def __init__(self, urls): self.urls = urls # Global Place To Store The Data: self.all_data = [] self.master_dict = {} # Run The Scraper: asyncio.run(self.main()) async def fetch(self, session, url): try: async with session.get(url) as response: text = await response.text() return text, url except Exception as e: print(str(e)) async def main(self): tasks = [] headers = { "user-agent": "Mozilla/5.0 (compatible; Googlebot/2.1; +http://www.google.com/bot.html)"} async with aiohttp.ClientSession(headers=headers) as session: for url in self.urls: tasks.append(self.fetch(session, url)) htmls = await asyncio.gather(*tasks) self.all_data.extend(htmls) # Storing the raw HTML data. for html in htmls: if html is not None: url = html[1] self.master_dict[url] = {'Raw Html': html[0]} else: continue ```

``` package main import ( "encoding/json" "fmt" "io/ioutil" "log" "net/http" ) const API string = "https://pkgstats.archlinux.de/api/" type PkgPopularity struct { Name string Popularities []float64 } type PackagePopularity struct { Name string `json:"name"` Samples int `json:"samples"` Count int `json:"count"` Popularity float64 `json:"popularity"` StartMonth int `json:"startMonth"` EndMonth int `json:"endMonth"` } type Response struct { Total int `json:"total"` Count int `json:"count"` Limit int `json:"limit"` Offset int `json:"offset"` Query interface{} `json:"query"` PackagePopularities []PackagePopularity `json:"packagePopularities"` } func main() { /*browsers := []string{"firefox", "chromium", "google-chrome", "epiphany", "konqueror", "tor-browser", "vivaldi", "opera", "midori"} fmt.Println(get_popularities(browsers))*/ get_trending_packages() } func get_trending_packages() { fmt.Println(get_popularities(get_package_names())) } func get_popularities(pkgs []string) []PkgPopularity { var popularities []PkgPopularity for _, pkg := range pkgs { popularities = append(popularities, PkgPopularity{pkg, get_package_monthly_popularity(pkg)}) } return popularities } func get_total_packages() int { var response Response response = requestJSON("packages?limit=1") return response.Total } func get_package_names() []string { var packages []string var total = 50 // get_total_packages() var offset, limit int = 0, 100 for offset < total { relURL := "packages?limit=" + fmt.Sprint(limit) + "&offset=" + fmt.Sprint(offset) var response Response response = requestJSON(relURL) for _, pkg := range response.PackagePopularities { packages = append(packages, pkg.Name) } offset += limit } return packages } func get_package_monthly_popularity(pkg string) []float64 { relURL := "packages/" + pkg + "/series?startMonth=201009" var response Response response = requestJSON(relURL) var popularities []float64 for _, pkg := range response.PackagePopularities { popularities = append(popularities, pkg.Popularity) } return popularities } func requestJSON(relURL string) Response { resp, err := http.Get(API + relURL) if err != nil { log.Fatal(err) } defer resp.Body.Close() body, err := ioutil.ReadAll(resp.Body) if err != nil { log.Fatal(err) } var response Response err = json.Unmarshal(body, &response) if err != nil { log.Fatal(err) } return response } ```

Migrate stash database to virtual filesystem
``` import logging import os import pprint import pytest import sqlite3 import subprocess import sys import traceback from typing import Dict, List, Tuple DRY_RUN = False STASH_DB_PATH = "/run/media/user/T/video/stash/stash-go.sqlite" # Migrate only scenes in the following location # Leave empty to import all scenes in the database LOCATION = "" SPLITCHAR = "_" # Supertag or TMSU VFS = "Supertag" pp = pprint.PrettyPrinter(indent=4) def migrate_data_to_vfs() -> None: connect_to_sqlite_db() scenes_info = get_scenes_info() for scene_info in scenes_info: try: if not os.path.isfile(scene_info["path"]): print(f'File not exists: {scene_info["path"]}') continue if not scene_info["tags"] or len(scene_info["tags"]) == 0: print(f'File with no tags: {scene_info["path"]}') continue command = prepare_command(scene_info) if DRY_RUN: print(command) else: subprocess.check_output(command) except: print("Failed to process") pp.pprint(scene_info) traceback.print_exc() cursor.close() sqlite_connection.close() def connect_to_sqlite_db() -> None: global sqlite_connection, cursor try: sqlite_connection = sqlite3.connect(STASH_DB_PATH) cursor = sqlite_connection.cursor() except sqlite3.Error as error: input("Press Enter to continue...") sys.exit(1) def get_scenes_info() -> List[Dict]: query = build_query() scenes_info = [] for row in cursor.execute(query).fetchall(): scene_id = str(row[0]) scene_path = str(row[1]) scene_date = str(row[2]) scene_info = { "id": scene_id, "path": scene_path, "year": get_scene_year(scene_date), "tags": get_tags(row) } scenes_info.append(scene_info) return scenes_info def build_query() -> str: query = """ SELECT id, path, date, studio_id FROM scenes """ if LOCATION: query += f"WHERE path LIKE '{LOCATION}%'" return query def get_scene_year(scene_date: str) -> str: try: return scene_date.split("-")[0] except: return scene_date def test_get_scene_year(): assert get_scene_year("None") == "None" assert get_scene_year("2021-05-02") == "2021" def get_tags(row: Tuple) -> List[str]: tags = [] if not row: return tags tags.append(get_studio_name_from_id(str(row[3]))) tags.extend(get_performers_from_scene_id(str(row[0]))) tags.extend(get_tags_from_scene_id(str(row[0]))) return [tag.replace(" ", SPLITCHAR) for tag in tags] def get_studio_name_from_id(studio_id: str) -> str: if not studio_id or studio_id == "None": return "" sql = f""" SELECT name FROM studios WHERE id={studio_id}; """ return str(cursor.execute(sql).fetchall()[0][0]) def get_performers_from_scene_id(scene_id: str) -> List[str]: sql = f""" SELECT performer_id FROM performers_scenes WHERE scene_id={scene_id}; """ performers = cursor.execute(sql).fetchall() return get_performers_names(performers) def get_performers_names(record: List) -> List[str]: performers = [] for row in record: performer_id = str(row[0]) sql = f""" SELECT name FROM performers WHERE id={performer_id}; """ performers.append(str(cursor.execute(sql).fetchall()[0][0])) return performers def get_tags_from_scene_id(scene_id: str) -> List[str]: sql = f""" SELECT tag_id FROM scenes_tags WHERE scene_id={scene_id}; """ tag_id = cursor.execute(sql).fetchall() return get_list_tag_names(tag_id) def get_list_tag_names(record: List) -> List[str]: tags = [] for row in record: tag_id = str(row[0]) sql = f""" SELECT name FROM tags WHERE id={tag_id}; """ tags.append(str(cursor.execute(sql).fetchall()[0][0])) return tags def prepare_command(scene_info: Dict) -> List[str]: if VFS == "Supertag": return ["tag", "ln", f'{scene_info["path"]}', format_tags(scene_info["tags"])] elif VFS == "TMSU": cmd = ["tmsu", "tag", f'{scene_info["path"]}', format_tags(scene_info["tags"])] if scene_info["year"] and scene_info["year"] != "None": cmd.append(f'year={scene_info["year"]}') return cmd def format_tags(tags: List[str]) -> str: if VFS == "Supertag": return "/".join(tags) if VFS == "TMSU": return "_".join(tags) def test_prepare_command(): with open("/tmp/test.txt", "a") as f: f.write("test") scene_info = { 'path': '/tmp/test.txt', 'tags': ['tag1', 'tag2'] } cmd = prepare_command(scene_info) if VFS == "Supertag": assert cmd == ["tag", "ln", "/tmp/test.txt", "tag1/tag2"] if VFS == "TMSU": assert cmd == ["tmsu", "tag", "/tmp/test.txt", "tag1_tag2"] assert subprocess.check_output(cmd) == b"" subprocess.check_output(["tag", "rmdir", "tag1"]) subprocess.check_output(["tag", "rmdir", "tag2"]) def test_prepare_command_with_spaces(): with open("/tmp/test 2.txt", "a") as f: f.write("test") scene_info = { 'path': '/tmp/test 2.txt', 'tags': ['tag1', 'tag2'] } cmd = prepare_command(scene_info) if VFS == "Supertag": assert cmd == ["tag", "ln", "/tmp/test 2.txt", "tag1/tag2"] if VFS == "TMSU": assert cmd == ["tmsu", "tag", "/tmp/test 2.txt", "tag1_tag2"] assert subprocess.check_output(cmd) == b"" if __name__ == "__main__": migrate_data_to_vfs() ```

Onlyfans
Got'em! 😈 Thanks for the click! If you actually want to send me money, send me 0.69 or 4.20 doge. 😘 dogecoin (doge): DRVaGKw9WpWbBaRaFKsEp8AWa2UYjmwfiM https://opengameart.org/content/rusty-old-fan
fedilink

cross-posted from: https://lemmy.ml/post/348257 > Copypasta in case website goes down: > > Language: English > Who Are We? > Campaigns > Press > Become Active > Sex, Abortion, & Birth > Safe Sex > Am I Pregnant? > How to Abort at home with Pills (misoprostol, cytotec)? > Safe birth with Misoprostol > Questions and Answers > Sexual health and abortion services worldwide > Warning, fake abortion pills for sale online!! > Resources > Donate! > Contact > Sign up for newsletters > info@womenonwaves.org > Share this page > > How to Abort at home with Pills (misoprostol, cytotec)? > > The best and safest way a woman can do an abortion herself until the 12th week of pregnancy is with the use of two medicines called Mifepristone (also known as the abortion pill, RU 486, Mifegyn, Mifeprex, Zacafemyl), and Misoprostol (also known as Cytotec, Arthrotec, Oxaprost, Cyprostol, Mibetec, Prostokos or Misotrol). If you live in a country where there is no access to safe abortion services and you would like to obtain a medical abortion with Mifepristone and Misoprostol, please go to Women on Web (www.womenonweb.org). > > There are 2 ways to do a medical abortion safely and effectively: > > > 1- Abortion pills through Women on Web > > To obtain a medical abortion with Mifepristone and Misoprostol, please go to Women on Web (www.womenonweb.org) and do the online consultation through https://www.womenonweb.org/en/i-need-an-abortion to get a safe medical abortion using Mifepristone and Misoprostol. Women on Web is an on-line medical abortion referral service that will refer your consultation to a licensed doctor. You will also be asked to make a donation of 70, 80 or 90 euros depending on your economic circumstance and where you live, to make sure that the service continues to be available to help all women. You can make the donation using a credit card or bank transfer. > > If the website is blocked please send an email to:info@womenonweb.org > 2- On this webpage you can find more information about doing an abortion with the use of Misoprostol alone (approximately 94% effective). > > It is very important that you know how many weeks pregnant you are. Have you taken a pregnancy test to confirm your pregnancy? If you cannot have an ultrasound, calculate the duration of pregnancy by counting the number of days since the first day of your last menstrual period. > > Using Misoprostol (or Cytotec) alone to cause an abortion will be successful 94% of the time. If it is not effective the first time, you can try again after 3 days. The information is based on research by the World Health Organization. > Women who live in a country where they have the possibility to have a safe and legal abortion, should go to a doctor. For abortion clinics worldwide, see https://www.womenonwaves.org/en/map/country > If you live in a country where there is no access to safe abortion services and you would like to obtain a medical abortion with Mifepristone and Misoprostol, please go to Women on Web (www.womenonweb.org). > Some women attempt to have an abortion by placing sharp or dirty objects into the womb or by punching the belly. This is very dangerous and should never be done because there is a very high risk of wounding the insides of the woman, infection, heavy bleeding and even death. > > For many women, ending a pregnancy is a difficult decision. When the woman cannot discuss the abortion or alternatives with a healthcare provider, we advise her to talk about it with a good friend or a relative. We strongly advise any young girl to talk with her parents or another adult she trusts about her situation, her decision and the abortion procedure. > Women who are sure that they want to end their pregnancy and have no other means should print and study the instructions carefully first. It is best to discuss them with a friend. A woman should never do this alone. > > If you have any questions about this method or experiences you want to share, after reading the information below, send email to info@womenonweb.org > How does an abortion with Misoprostol work? > > Misoprostol for medical abortion works best in the first 12 weeks of pregnancy. After that, there is an increased risk of a complication and need for medical attention. If you are considering using misoprostol after 12 weeks, please contact info@womenonweb.org for instructions; these instructions are for women who are 12 weeks or earlier in their pregnancy. > > Misoprostol causes contractions of the womb. As a consequence, the womb expels the pregnancy. A woman can get painful cramps, vaginal blood loss that is more than a normal menstruation, nausea, vomiting and diarrhoea. There is a risk of heavy bleeding for which a woman will have to be treated by a doctor. > The chance that an abortion with Misoprostol will be successful is 94%. Misoprostol is available in pharmacies in almost all countries. > The experience and risks of an abortion caused by Misoprostol are similar to those of a spontaneous miscarriage. > > Miscarriage happens spontaneously in 15-20% of all pregnancies. > > The treatment of complications is the same as those of a spontaneous abortion (miscarriage). If there is a problem, a woman can always go to the hospital or any doctor. The doctor will treat her as if she had a spontaneous miscarriage. There is no way the doctor will know that the woman took medicines. > > We will now provide some important information that every woman who thinks about inducing an abortion with medicines should know. > A woman should make sure she is pregnant. > > She can do a pregnancy test or have an ultrasound. > Misoprostol should only be used if a woman is 100% sure that she wants to end the pregnancy. > A woman should try to have an ultrasound before taking Misoprostol. > > An ultrasound shows whether the pregnancy is in the womb and the length (number of weeks) of a woman's pregnancy. > Misoprostol should not be used after 12 or more weeks of pregnancy. > > A pregnancy of twelve weeks means 84 days (12 weeks) after the first day of the last menstrual period. If a woman thinks she has been pregnant for more than twelve weeks, or if the ultrasound shows this, we do not advise to take Misoprostol unless the woman has medical supervision. > The medicine still works, but the risk of heavy bleeding, serious pain and complications increase the longer the pregnancy lasts. > A woman should not do the abortion alone. > > While having the abortion, it is important to have someone close by; this can be the partner, a friend or a relative who knows about the abortion and who can help in case of complications. Once the bleeding starts, someone should stay in contact with the woman to be able to help in case complications occur. > Misoprostol can only be used without medical guidance when a woman has no serious illness. > > Most illnesses are no problem. Some serious illnesses, such as, for instance, severe anaemia, can create problems because of the heavy blood loss involved. > Serious illnesses are sometimes a reason for a legal abortion, even in countries with restrictive laws. > > Do not use alcohol or drugs during the treatment!!! The woman must be able to pay close attention to what is happening in her body. If the cramps are very painful, she can use Ibuprofen, or a hot water bottle or heating pad, but never alcohol or drugs. > Misoprostol should not be used when there is a possibility of an ectopic (or extra-uterine) pregnancy. > > An ectopic (or extra-uterine pregnancy) is not in the womb (uterus). An ectopic pregnancy can be detected by having an ultrasound. Treatment by a gynaecologist is then necessary to ensure the health of the woman. If not treated, there is a risk of heavy internal bleeding due to rupturing of the fallopian tube. > Gynaecologists treat women for this condition in all countries, even in countries where abortion is illegal. An ectopic pregnancy cannot be treated with Misoprostol. > Misoprostol should not be used if the woman has an intra uterine device (IUD). > > An IUD is a contraceptive, a small coil of about 3 cm inserted by a doctor in the womb to prevent pregnancy. A Woman who has an IUD and is pregnant must have an ultrasound made because the risk of an ectopic pregnancy is higher. If the pregnancy is in the uterus, it is necessary to have the IUD removed before using doing the abortion. > Misoprostol should only be used when transportation within a few hours to a hospital is possible. > > That way, if complications occur, medical aid will be near. > Misoprostol should never be used if the woman is allergic to Misoprostol or any other prostaglandin. > > This is a rare condition, which a woman will be aware of if she has used these medicines and had such a reaction before. If she has never used the medicine before, she cannot have experienced an allergic reaction. > There is a possibility that the attempt to cause an abortion with Misoprostol will fail. > > The chance that using Misoprostol will cause an abortion is 94%. The treatment has failed if the medicines do not cause any bleeding at all or there was bleeding but the pregnancy still continued. The woman can try to use the medicines again after a few days, but this can fail again. There is only an ongoing pregnancy in 6% of cases. > > > If more than 14 days after the use of Misoprostol no abortion has occurred, and if no doctor is willing to help, there remains no other option than to travel to another country to have a legal abortion, contact women on web, or to keep the pregnancy. > There is a small increased risk of birth defects such as deformities of the hands or feet and problems with the nerves of the foetus, if the pregnancy continues after attempting abortion with these medicines. Some doctors might consider this as a reason for a legal abortion, so try to find one. > A possible sexual transmitted infection should be treated. > > If there is a risk of a sexual transmitted infection (STI, also known as a sexually transmitted disease, STD) such as Chlamydia or Gonorrhoea, arrange an examination with

Nicotine+ Leech Detector plugin
**I've set the Leech Detector plugin to ban, instead of sending a warning message, when a user has less than 2k files or 100 folders. I lift the bans everyday so you'll be able to download from me tomorrow if you have shared enough files and folders. Thanks :)** If you have more than those files and folders and you still get banned, it may be because you haven't scanned them yet, or you have closed ports, or a server error, or whatever... There is nothing I can do about it. Share as many interesting files as possible. If everyone shared only a few files, Nicotine+ wouldn't be such a great network. I have many of my files shared on fopnu, in case you don't want to wait for the queue. - https://fopnu.com If you are a programmer take a look at this projects in case you want to collaborate. Websites for collaborative metadata curation and hash storage: - [stash-box](https://github.com/stashapp/stash-box) - [MuCats](https://github.com/zlatinb/mucats) Other interesting posts: - [Describing my perfect p2p file-sharing program](https://lemmy.ml/post/622702) - [What are your opinions on the different p2p file-sharing programs available for Linux?](https://lemmy.ml/post/621734) - [What are your favorite file-sharing applications?](https://lemmy.ml/post/335082) - [Where is the true succesor to eMule?](https://lemmy.ml/post/332745) - [What are your favorite file-sharing programs?](https://lemmy.ml/post/335082) - [Best p2p network to bulk share stuff?](https://reddit.com/r/Piracy/comments/ayo1hu/best_p2p_network_to_bulk_share_stuff/) - [Alternatives to soulseek](https://reddit.com/r/musichoarder/comments/plt569/good_alternatives_to_soulseek/) - [Comparison of file-sharing applications](https://en.wikipedia.org/wiki/Comparison_of_file-sharing_applications) - [List of P2P protocols](https://en.wikipedia.org/wiki/List_of_P2P_protocols) - [How to search and download unpopular and old files on the internet](https://medium.com/@ValdikSS/how-to-search-and-download-unpopular-and-old-files-on-the-internet-e5947ef507ba) I would like to change the plugin so that people get the ban lifted after they've shared enough files and folders. `/usr/lib/python3.10/site-packages/pynicotine/plugins/leech_detector/__init__.py` ``` from pynicotine import slskmessages from pynicotine.pluginsystem import BasePlugin class Plugin(BasePlugin): def __init__(self, *args, **kwargs): super().__init__(*args, **kwargs) self.settings = { 'message': '[Automatic Message] Banned for sharing few files or folders. Read this to get unbanned: https://lemmy.ml/post/338552', 'num_files': 2000, 'num_folders': 100, 'open_private_chat': True } self.metasettings = { 'message': { 'description': ('Private chat message to send to leechers. Each line is sent as a separate message, ' 'too many message lines may get you temporarily banned for spam!'), 'type': 'textview' }, 'num_files': { 'description': 'Require users to have a minimum number of shared files:', 'type': 'int', 'minimum': 0 }, 'num_folders': { 'description': 'Require users to have a minimum number of shared folders:', 'type': 'int', 'minimum': 1 }, 'open_private_chat': { 'description': 'Open chat tabs when sending private messages to leechers', 'type': 'bool' } } self.probed = {} self.str_action = "" def loaded_notification(self): min_num_files = self.metasettings['num_files']['minimum'] min_num_folders = self.metasettings['num_folders']['minimum'] if self.settings['num_files'] < min_num_files: self.settings['num_files'] = min_num_files if self.settings['num_folders'] < min_num_folders: self.settings['num_folders'] = min_num_folders for list_name in ("banlist", "ipblocklist"): # "ignorelist", "ipignorelist" self.config.sections["server"][list_name].clear() self.log( "Ready to ban leechers for not having a minimum of %d files in %d shared public folders.", (self.settings['num_files'], self.settings['num_folders']) ) def upload_queued_notification(self, user, virtual_path, real_path): if user in self.probed: # We already have stats for this user. return self.probed[user] = 'requesting' self.core.queue.append(slskmessages.GetUserStats(user)) def user_stats_notification(self, user, stats): if user not in self.probed: # We did not trigger this notification return if self.probed[user] != 'requesting': # We already dealt with this user. return if stats['files'] >= self.settings['num_files'] and stats['dirs'] >= self.settings['num_folders']: self.probed[user] = 'okay' return if user in (i[0] for i in self.config.sections["server"]["userlist"]): self.probed[user] = 'buddy' return self.core.network_filter.ban_user(user) self.core.network_filter.block_user_ip(user) self.probed[user] = 'processed' self.log("Banned leecher %s for sharing only %s files in %s folders. Message sent.", (user, stats['files'], stats['dirs'])) if not self.settings['message']: self.log("Leecher %s doesn't share enough files. No message is specified in plugin settings.", user) return for line in self.settings['message'].splitlines(): self.send_private(user, line, show_ui=self.settings['open_private_chat'], switch_page=False) def incoming_private_chat_notification(self, user, line): if "added files" not in line.lower() or stats['files'] < self.settings['num_files'] or stats['dirs'] < self.settings['num_folders']: return self.core.network_filter.unban_user(user) self.core.network_filter.unblock_user_ip(user) ```

Get Penny Dreadful confirmed playable cards
``` import json import math import re import requests import time from typing import Dict, List def parse(path): file = open(path) mydict = {} for line in file.readlines(): number, cardname = line.split(' ', 1) mydict[cardname] = mydict.get(cardname, 0) + int(number) return mydict def get_pd_confirmed_playable_cards(): cards = get_cards_from_api() cards = sort_cards_by_playability(cards) cards = dict_list_to_str_list(cards, 'name') save_list_by_lines(cards, 'want.txt') def get_cards_from_api() -> List: page = 0 pages = -1 pageSize = 1000 cards = [] api = f"https://pennydreadfulmagic.com/api/rotation/cards/?pageSize={pageSize}&page=" while True: j = json.loads(requests.get(api + str(page)).text) if page == 0: pages = math.floor(j['total'] / pageSize) cards += filter_dict_list(filter_legal_cards(j['objects']), ['name', 'rank']) if page > pages: break page += 1 time.sleep(0.1) return cards def filter_legal_cards(cards: List) -> List: return [card for card in cards if card['status'] == 'Legal'] def filter_dict_list(l: List[Dict], keys: List) -> List[Dict]: return [ { k: d[k] for k in keys if k in d } for d in l ] def sort_cards_by_playability(cards: List) -> List: return sorted(cards, key = lambda i: i['rank']) def dict_list_to_str_list(l: List[Dict], k: str) -> List[str]: return [d[k] for d in l] def save_list_by_lines(l, f: str): with open(f, "w") as output: for i in l: output.write("%s\n" % i) def process_wanted_cards(f: str) -> None: cards = get_wanted_cards_from_file(f) save_list_by_lines(cards, f) def get_wanted_cards_from_file(f: str) -> List[str]: cards = [] with open(f, 'r') as input: lines = input.readlines() for line in lines: res = process_line(line) if res is None: continue card, percent = res if percent >= 50: cards.append("4 " + card) return cards def process_line(s: str) -> tuple | None: array = s.split("\t") if len(array) < 5: return name = array[1] percent = get_percentage(array[2]) return name, percent def get_percentage(s: str) -> int: return int(re.search(r'\(([0-9]*)%\)', s).group(1)) def get_missing_cards(): most_played = parse('/home/user/docs/text/games/mtg/most_played_missing_pd_cards/wanted.txt') got = parse('/home/user/docs/text/games/mtg/most_played_missing_pd_cards/got.txt') need = {} for cardname, number in most_played.items(): n_want = number - got.get(cardname, 0) if n_want > 0: need[cardname] = n_want for cardname, number in need.items(): print(str(number) + " " + cardname) # sed -i '/^$/d' file.txt if __name__ == "__main__": #process_wanted_cards('wanted.txt') get_missing_cards() ```

A query param is like
Basically... A query param is like ?id=100. So https://rakka.tk/book?id=5&chapter=1 has two query params. And the significance is that it's in the URL. So when the server sees it, if the URL is logged, it'll contain all of that. URLs are pretty much always logged. So now you have auth tokens (effectively passwords) in logs, which are rarely encrypted or protected, since logs aren't meant to contain sensitive information.
fedilink

Pastebin -> sub migrated
!pastebin

    Migrating too https://lemmy.ca/c/pastebin

    Text storage sublemmy. It can be used to help promote lemmy by linking to c/pastebin over say a commercial pastebin website

    • 0 users online
    • 1 user / day
    • 1 user / week
    • 2 users / month
    • 4 users / 6 months
    • 18 subscribers
    • 12 Posts
    • 2 Comments
    • Modlog