URLWATCH-FILTERS(5) مستندات urlwatch URLWATCH-FILTERS(5)

urlwatch-filters - فیلتر کردن خروجی و داده‌های تفاوت (diff) در وظایف urlwatch

urlwatch --edit

برای هر وظیفه می‌توان دو مرحله فیلتر پیکربندی کرد که یک یا چند فیلتر به‌ترتیب پس از یکدیگر پردازش می‌شوند:

  • اعمال‌شده بر روی صفحه بارگیری‌شده قبل از محاسبه تفاوت تغییرات (filter)
  • اعمال‌شده بر روی نتیجه تفاوت (diff) قبل از گزارش تغییرات (diff_filter)

هنگام ایجاد خط‌لوله فیلتر خود، ممکن است بخواهید پیش‌نمایشی از خروجی فیلترشده را مشاهده کنید. می‌توانید ابتدا وظیفه خود را پیکربندی کرده و سپس urlwatch را با دستور --test-filter اجرا کنید و اندیس (از --list) یا نشانی اینترنتی/مکان وظیفه مورد آزمایش را به آن ارسال نمایید:

urlwatch --test-filter 1   # آزمایش اولین وظیفه در فهرست
urlwatch --test-filter https://example.net/  # آزمایش وظیفه با نشانی داده‌شده

خروجی این دستور، متن ساده فیلترشده وظیفه خواهد بود؛ این همان خروجی است که (در اجرای واقعی urlwatch) ورودی الگوریتم تفاوت (diff) خواهد بود.

فیلتر filter فقط روی محتوای جدید اعمال می‌شود، زیرا محتوای قدیمی قبلاً هنگام دریافت فیلتر شده است. این بدان معناست که تغییرات در filter هنگام گزارش محتوای تغییرنیافته قابل مشاهده نیستند (برای جزئیات به Display مراجعه کنید)، و خروجی تفاوت (diff) بین (محتوای قدیمی با فیلتر در زمان دریافت محتوای قدیمی) و (محتوای جدید با فیلتر فعلی) خواهد بود.

هنگامی که urlwatch حداقل ۲ تصویر لحظه‌ای (snapshot) تاریخی از یک وظیفه را جمع‌آوری کرد (دو وضعیت متفاوت از یک صفحه وب)، می‌توانید از گزینه خط فرمان --test-diff-filter برای آزمایش تنظیمات diff_filter خود استفاده کنید؛ این گزینه از داده‌های تاریخی ذخیره‌شده به صورت محلی در حافظه موقت (cache) استفاده می‌کند.

فهرست فیلترهای توکار را می‌توان با استفاده از دستور زیر دریافت کرد:

urlwatch --features

در حال حاضر، فیلترهای زیر به صورت توکار موجود هستند:

  • beautify: زیباسازی و مرتب‌سازی HTML
  • css: فیلتر کردن XML/HTML با استفاده از انتخاب‌گرهای CSS
  • csv2text: تبدیل CSV به متن ساده
  • element-by-class: دریافت تمام عناصر HTML بر اساس کلاس (class)
  • element-by-id: دریافت یک عنصر HTML بر اساس شناسه (ID) آن
  • element-by-style: دریافت تمام عناصر HTML بر اساس استایل (style)
  • element-by-tag: دریافت یک عنصر HTML بر اساس برچسب (tag) آن
  • format-json: تبدیل به JSON قالب‌بندی‌شده
  • grep: فیلتر کردن و نگه‌داشتن تنها خطوط منطبق با یک عبارت باقاعده
  • grepi: حذف خطوط منطبق با یک عبارت باقاعده
  • hexdump: تبدیل داده‌های دودویی به قالب hex dump
  • html2text: تبدیل HTML به متن ساده
  • pdf2text: تبدیل PDF به متن ساده
  • pretty-xml: چاپ خوانا و مرتب (pretty-print) XML
  • ical2text: تبدیل iCalendar https://en.wikipedia.org/wiki/ICalendar به متن ساده
  • ocr: تبدیل متن درون تصاویر به متن ساده با استفاده از Tesseract OCR
  • re.sub: جایگزینی متن با عبارات باقاعده با استفاده از re.sub پایتون
  • re.findall: یافتن تمام تطابق‌های غیرهمپوشان با استفاده از re.findall پایتون
  • reverse: معکوس کردن موارد ورودی
  • sha1sum: محاسبه چکسام SHA-1 محتوا
  • shellpipe: فیلتر کردن با استفاده از یک دستور شل
  • sort: مرتب‌سازی موارد ورودی
  • remove-duplicate-lines: حذف خطوط تکراری (حساس به حروف بزرگ و کوچک)
  • strip: حذف فاصله‌های خالی ابتدا و انتهای متن
  • striplines: حذف فاصله‌های خالی ابتدا و انتهای هر خط
  • xpath: فیلتر کردن XML/HTML با استفاده از عبارات XPath
  • jq: فیلتر کردن، تبدیل و استخراج مقادیر از JSON

شما می‌توانید تنها یک عنصر خاص HTML را با فیلتر توکار استخراج کنید، برای مثال جهت استخراج <div id="something">.../<div> از یک صفحه، می‌توانید از مورد زیر در urls.yaml خود استفاده کنید:

url: http://example.org/idtest.html
filter:
  - element-by-id: something

همچنین می‌توانید فیلترها را زنجیره‌سازی کنید، تا بتوانید html2text را روی نتیجه اجرا نمایید:

url: http://example.net/id2text.html
filter:
  - element-by-id: something
  - html2text

فایل نمونه urls.yaml همچنین نحوه استفاده از فیلترهای توکار را نشان می‌دهد؛ در اینجا از ۳ فیلتر استفاده شده است: html2text، grep خطی و حذف فاصله‌های خالی برای دریافت تنها یک فیلد اطلاعاتی خاص از یک صفحه وب:

url: https://example.net/version.html
filter:
  - html2text
  - grep: "Current.*version"
  - strip

اگر می‌خواهید فقط برچسب body را استخراج کنید، می‌توانید از این فیلتر استفاده کنید:

url: https://example.org/bodytag.html
filter:
  - element-by-tag: body

برای فیلتر کردن بر اساس یک عبارت XPath https://www.w3.org/TR/1999/REC-xpath-19991116/، می‌توانید از فیلتر xpath به این صورت استفاده کنید:

url: https://example.net/xpath.html
filter:
  - xpath: /html/body/marquee

این فیلتر تنها عناصر <marquee> را که مستقیماً زیر عنصر <body> قرار دارند (که آن هم به نوبه خود باید زیر عنصر <html> سند باشد) فیلتر کرده و بقیه موارد را حذف می‌کند.

برای نمونه‌های دیگر، صفحه XPath Examples https://msdn.microsoft.com/en-us/library/ms256086(v=vs.110).aspx متعلق به مایکروسافت را مشاهده کنید. شما همچنین می‌توانید XPath یک گره <html> را در ابزارهای توسعه‌دهنده کرومیوم/گوگل کروم با کلیک راست روی گره و انتخاب copy XPath پیدا کنید.

برای فیلتر کردن بر اساس یک انتخاب‌گر CSS https://www.w3.org/TR/2011/REC-css3-selectors-20110929/، می‌توانید از فیلتر css به این صورت استفاده کنید:

url: https://example.net/css.html
filter:
  - css: ul#groceries > li.unchecked

این دستور تنها برچسب‌های <li class="unchecked"> را که مستقیماً زیر عناصر <ul id="groceries"> قرار دارند فیلتر می‌کند.

برخی محدودیت‌ها و افزونه‌ها وجود دارند که در مستندات cssselect https://cssselect.readthedocs.io/en/latest/#supported-selectors توضیح داده شده‌اند.

به‌طور پیش‌فرض، فیلترهای XPath و CSS برای اسناد HTML تنظیم شده‌اند. با این حال، امکان استفاده از آن‌ها برای اسناد XML نیز وجود دارد (این مثال‌ها یک خوراک RSS را تجزیه کرده و تنها عناوین و تاریخ‌های انتشار را فیلتر می‌کنند):

url: https://example.com/blog/xpath-index.rss
filter:
  - xpath:
      path: '//item/title/text()|//item/pubDate/text()'
      method: xml
url: http://example.com/blog/css-index.rss
filter:
  - css:
      selector: 'item > title, item > pubDate'
      method: xml
  - html2text: re

برای تطابق یک عنصر در یک فضای نام XML (namespace) https://www.w3.org/TR/xml-names/، از یک پیشوند فضای نام قبل از نام برچسب استفاده کنید. از یک : برای جدا کردن پیشوند فضای نام و نام برچسب در عبارت XPath، و از یک | در انتخاب‌گر CSS استفاده کنید.

url: https://example.net/feed/xpath-namespace.xml
filter:
  - xpath:
      path: '//item/media:keywords/text()'
      method: xml
      namespaces:
        media: http://search.yahoo.com/mrss/
url: http://example.org/feed/css-namespace.xml
filter:
  - css:
      selector: 'item > media|keywords'
      method: xml
      namespaces:
        media: http://search.yahoo.com/mrss/
  - html2text

همچنین می‌توانید از عبارت XPath به صورت //*[name()='<tag_name>'] برای دور زدن کامل فضای نام استفاده کنید.

گزینه مفید دیگر در فیلترهای XPath و CSS گزینه exclude است. عناصری که توسط این عبارت exclude انتخاب می‌شوند، از نتیجه نهایی حذف می‌گردند. برای مثال، وظیفه زیر هیچ برچسب <a> در نتایج خود نخواهد داشت:

url: https://example.org/css-exclude.html
filter:
  - css:
      selector: body
      exclude: a

اگر فقط می‌خواهید زیرمجموعه‌ای از موارد بازگردانده‌شده توسط یک فیلتر انتخاب‌گر CSS یا XPath را دریافت کنید، می‌توانید از دو زیرفیلتر کمکی استفاده نمایید:

  • skip: تعداد عناصری که باید از ابتدا نادیده گرفته شوند (پیش‌فرض: 0)
  • maxitems: حداکثر تعداد عناصری که باید بازگردانده شوند (پیش‌فرض: بدون محدودیت)

برای مثال، اگر صفحه دارای چندین عنصر باشد، اما شما فقط بخواهید عنصر منطبق دوم و سوم را انتخاب کنید (اولی را نادیده بگیرید و حداکثر دو عنصر را بازگردانید)، می‌توانید از این فیلتر استفاده کنید:

url: https://example.net/css-skip-maxitems.html
filter:
  - css:
      selector: div.cpu
      skip: 1
      maxitems: 2

اگر چندین نتیجه در یک صفحه دریافت می‌کنید در حالی که فقط انتظار یک مورد را داشتید (برای مثال به این دلیل که صفحه شامل هر دو نسخه موبایل و دسکتاپ در همان سند HTML است و بسته به اندازه دیدگاه (viewport) یکی را از طریق CSS نشان می‌دهد/پنهان می‌کند)، می‌توانید از maxitems: 1 برای بازگرداندن تنها مورد اول استفاده کنید.

در برخی موارد، ترتیب موارد در یک صفحه وب ممکن است بدون تغییر محتوای واقعی به طور منظم تغییر کند. به‌طور پیش‌فرض، این حالت در خروجی diff به صورت حذف یک عنصر از یک بخش صفحه و درج آن در بخش دیگر صفحه نمایش داده می‌شود.

در مواردی که ترتیب موارد اهمیتی ندارد، می‌توان موارد منطبق را بر اساس حروف الفبا (واژه‌نگاشتی / lexicographically) مرتب کرد تا از گزارش‌های کاذب و اضافی ناشی از تغییر صرف ترتیب موارد در صفحه جلوگیری شود.

زیرفیلتر مربوطه برای فیلترهای css و xpath گزینه sort است و می‌تواند true یا false (پیش‌فرض) باشد:

url: https://example.org/items-random-order.html
filter:
  - css:
      selector: span.item
      sort: true

برای پایش متن یک فایل PDF، از فیلتر pdf2text استفاده می‌کنید. این فیلتر نیازمند نصب کتابخانه pdftotext https://github.com/jalan/pdftotext/blob/master/README.md#pdftotext و هر یک از وابستگی‌های وابسته به سیستم‌عامل https://github.com/jalan/pdftotext/blob/master/README.md#os-dependencies آن است.

این فیلتر باید اولین فیلتر در یک زنجیره از فیلترها باشد، زیرا داده‌های دودویی را دریافت کرده و داده‌های متنی را خروجی می‌دهد.

url: https://example.net/pdf-test.pdf
filter:
  - pdf2text
  - strip

اگر فایل PDF دارای رمز عبور است، می‌توانید رمز عبور آن را مشخص کنید:

url: https://example.net/pdf-test-password.pdf
filter:
  - pdf2text:
      password: urlwatchsecret
  - strip

فیلتر csv2text می‌تواند برای تبدیل داده‌های CSV به یک نمایش متنی زیباتر استفاده شود. این کار با ارائه یک format_string انجام می‌شود که یک رشته قالب‌بندی پایتون https://docs.python.org/3/library/string.html#format-string-syntax است.

اگر فایل CSV دارای سرآیند (header) باشد، رشته قالب‌بندی باید از نام‌های سرآیند به صورت حروف کوچک استفاده کند. برای مثال، فرض کنید یک فایل CSV حاوی داده‌هایی مانند زیر داریم:

Name;Company
Smith;Initech
Doe;Initech

یک رشته قالب‌بندی ممکن برای CSV فوق (به کلیدهای با حروف کوچک توجه کنید):

Mr {name} works at {company}

اگر هیچ سطر سرآیندی وجود نداشته باشد، باید از نشانه‌گذاری آرایه عددی استفاده کنید:

Mr {0} works at {1}

می‌توانید با پرچم ignore_header استفاده از اندیس‌های عددی را اجبار کنید.

کلید has_header می‌تواند برای اجبار در استفاده از خط اول یا نادیده گرفتن خط اول به عنوان سرآیند استفاده شود، در غیر این صورت از csv.Sniffer https://docs.python.org/3/library/csv.html#csv.Sniffer استفاده خواهد شد.

گاهی اوقات یک صفحه وب ممکن است بین مقایسه‌ها داده‌های یکسانی داشته باشد اما به ترتیب تصادفی ظاهر شود. اگر این اتفاق افتاد، می‌توانید قبل از مقایسه مرتب‌سازی را انجام دهید.

url: https://example.net/sorting.txt
filter:
  - sort

فیلتر sort یک پارامتر اختیاری separator می‌گیرد که جداکننده موارد را مشخص می‌کند (به‌طور پیش‌فرض مرتب‌سازی مبتنی بر خط است)، برای مثال برای مرتب‌سازی بندهای متنی (متن‌های جداشده با یک خط خالی):

url: http://example.org/paragraphs.txt
filter:
  - sort:
      separator: "\n\n"

این را می‌توان با گزینه بولی reverse ترکیب کرد که برای مرتب‌سازی و معکوس کردن با همان جداکننده مفید است (با استفاده از % به عنوان جداکننده، این مورد 3%2%4%1 را به 4%3%2%1 تبدیل می‌کند):

url: http://example.org/sort-reverse-percent.txt
filter:
  - sort:
      separator: '%'
      reverse: true

برای معکوس کردن ترتیب موارد بدون مرتب‌سازی، می‌توان از فیلتر reverse استفاده کرد. به‌طور پیش‌فرض خطوط را معکوس می‌کند:

url: http://example.com/reverse-lines.txt
filter:
  - reverse

این رفتار را می‌توان با استفاده از آرگومان اختیاری رشته جداکننده تغییر داد (مثلاً مواردی که با نماد خط عمودی (|) جدا شده‌اند، مانند 1|4|2|3 که به صورت 3|2|4|1 معکوس می‌شود):

url: http://example.net/reverse-separator.txt
filter:
  - reverse: '|'

همچنین می‌توان فیلتر را به صورت مفصل‌تر با یک دیکشنری مشخص کرد. در این مثال از "\n\n" برای جداسازی بندها (موارد جداشده با خط خالی) استفاده شده است:

url: http://example.org/reverse-paragraphs.txt
filter:
  - reverse:
      separator: "\n\n"

این نمونه‌ای است از نحوه پایش صفحه «releases» در گیت‌هاب برای یک پروژه خاص جهت دریافت آخرین نسخه منتشرشده، تا از انتشارهای جدید مطلع شوید:

url: https://github.com/tulir/gomuks/releases
filter:
  - xpath:
      path: //*[@class="Link--primary Link"]
      maxitems: 1
  - html2text:

این نسخه معادل برای برچسب‌های گیت‌هاب است:

url: https://github.com/thp/urlwatch/tags
filter:
  - xpath:
      path: //*[@class="Link--primary Link"]
      maxitems: 1
  - html2text:

و برای برچسب‌های گیت‌لب:

url: https://gitlab.com/chinstrap/gammastep/-/tags
filter:
  - xpath: (//a[contains(@class,"item-title ref-name")])[1]
  - html2text

همچنین می‌توان از jq برای فیلتر کردن استفاده کرد:

url: https://api.github.com/repos/voxpupuli/puppet-rundeck/tags
filter:
  - jq: '.[0].name'

می‌توانید از re.sub و re.findall برای اعمال عبارات باقاعده استفاده کنید.

می‌توان از re.sub برای حذف یا جایگزینی تمام نمونه‌های غیرهمپوشان متن منطبق استفاده کرد. مثال زیر فیلتر را ۳ بار اعمال می‌کند:

1.
فقط مشخص کردن یک رشته به عنوان مقدار، تطابق‌ها را با رشته خالی جایگزین می‌کند.
2.
الگوهای ساده را می‌توان با استفاده از «pattern» به عنوان عبارت و «repl» به عنوان جایگزین، با رشته دیگری جایگزین کرد.
3.
می‌توانید از گروه‌ها (()) استفاده کرده و با \1 (و غیره..) به آن‌ها ارجاع به عقب دهید تا گروه‌ها را در رشته جایگزین قرار دهید.

مقدار پیش‌فرض repl رشته خالی است که باعث حذف رشته‌های منطبق می‌شود.

url: https://example.com/regex-substitute.html
filter:
    - re.sub: '\s*href="[^"]*"'
    - re.sub:
        pattern: '<h1>'
        repl: 'HEADING 1: '
    - re.sub:
        pattern: '</([^>]*)>'
        repl: '<END OF TAG \1>'

می‌توان از re.findall برای یافتن تمام تطابق‌های غیرهمپوشان یک عبارت باقاعده استفاده کرد. هر تطابق در یک خط جداگانه خروجی داده می‌شود. مثال زیر فیلتر را دو بار اعمال می‌کند:

1.
از یک گروه (()) و ارجاع به عقب (\1) برای استخراج تاریخ از رشته ورودی استفاده می‌کند.
2.
اعداد موجود در تاریخ را به خطوط جداگانه تقسیم می‌کند.

اگر repl مشخص نشود، کل تطابق در خروجی گنجانده خواهد شد.

url: https://example.com/regex-findall.html
filter:
    - re.findall:
        pattern: 'The next draw is on (\d{4}-\d{2}-\d{2}).'
        repl: '\1'
    - re.findall: '\d+'

نکته: هنگام استفاده از HTML یا XML، معمولاً بهتر است از انتخاب‌گرهای CSS یا عبارات XPATH استفاده کنید. HTML و XML را نمی‌توان با استفاده از عبارات باقاعده https://stackoverflow.com/a/1732454/1047040 به‌درستی تجزیه کرد. اگر انتخاب‌گر CSS یا XPATH نتواند انتخاب هدفمند مورد نیاز را ارائه دهد، استفاده از فیلتر html2text در ابتدا و سپس استفاده از re.findall می‌تواند الگوی مناسبی باشد.

اگر می‌خواهید پرچم‌ها را (مانند re.MULTILINE) در فیلترهای re.sub یا re.findall فعال کنید، از یک «پرچم درون‌خطی» استفاده نمایید؛ در اینجا چند نمونه آورده شده است:

  • re.MULTILINE: (?m) (باعث می‌شود ^ با ابتدای خط و $ با انتهای خط تطابق یابد)
  • re.DOTALL: (?s) (باعث می‌شود . با خط جدید (newline) نیز تطابق یابد)
  • re.IGNORECASE: (?i) (انجام تطابق بدون حساسیت به حروف بزرگ و کوچک)

این به شما امکان می‌دهد برای مثال تمام فاصله‌های ابتدایی (تنها نویسه فاصله و تب) را حذف کنید:

url: http://example.com/leading-spaces.txt
filter:
  - re.sub: '(?m)^[ \t]*'

اگرچه فیلترهای توکار برای پردازش نشانه‌گذاری‌هایی مانند HTML و XML قدرتمند هستند، در برخی موارد ممکن است از قبل بدانید چگونه محتوای خود را با استفاده از یک دستور یا اسکریپت شل فیلتر کنید. فیلتر shellpipe به شما امکان می‌دهد یک شل را اجرا کرده و دستورات سفارشی را برای فیلتر کردن محتوا اجرا نمایید.

داده‌های متنی که باید فیلتر شوند در ورودی استاندارد (stdin) فرایند شل نوشته می‌شوند و خروجی فیلتر از خروجی استاندارد (stdout) شل گرفته خواهد شد.

برای مثال، اگر می‌خواهید از ابزار grep با گزینه تطابق غیرحساس به بزرگی و کوچکی حروف (-i) و چاپ تنها بخش منطبق خط (-o) استفاده کنید، می‌توانید این را به عنوان فیلتر shellpipe مشخص نمایید:

url: https://example.net/shellpipe-grep.txt
filter:
  - shellpipe: "grep -i -o 'price: <span>.*</span>'"

این ویژگی همچنین به شما امکان می‌دهد از تک‌خطی‌های sed(1)، awk(1) و perl(1) برای پردازش متن استفاده کنید (البته هر ابزار متنی که در یک شل کار کند قابل استفاده است). برای مثال، این تک‌خطی awk(1) شماره خط را به ابتدای هر خط اضافه می‌کند:

url: https://example.net/shellpipe-awk-oneliner.txt
filter:
  - shellpipe: awk '{ print FNR " " $0 }'

همچنین می‌توانید از یک دستور چندخطی برای یک اسکریپت شل پیشرفته‌تر استفاده کنید (| در YAML نشان‌دهنده شروع یک بلوک متنی است):

url: https://example.org/shellpipe-multiline.txt
filter:
  - shellpipe: |
      FILENAME=`mktemp`
      # Copy the input to a temporary file, then pipe through awk
      tee $FILENAME | awk '/The numbers for (.*) are:/,/The next draw is on (.*)./'
      # Analyze the input file in some other way
      echo "Input lines: $(wc -l $FILENAME | awk '{ print $1 }')"
      rm -f $FILENAME

درون اسکریپت shellpipe، دو متغیر محیطی برای سفارشی‌سازی بیشتر تنظیم خواهند شد (این می‌تواند زمانی مفید باشد که یک فایل اسکریپت شل خارجی دارید که به عنوان فیلتر برای چندین وظیفه استفاده می‌شود، اما نیاز دارد با هر وظیفه به شکلی کمی متفاوت رفتار کند):

متغیر محیطی محتوا
$URLWATCH_JOB_NAME نام وظیفه (کلید name در YAML وظایف)
$URLWATCH_JOB_LOCATION نشانی وب وظیفه، یا خط فرمان (برای وظایف شل)

فیلتر ocr از موتور Tesseract OCR https://github.com/tesseract-ocr برای تبدیل متن درون تصاویر به متن ساده استفاده می‌کند. این فیلتر نیازمند نصب دو ماژول پایتون است: pytesseract https://github.com/madmaze/pytesseract و Pillow https://python-pillow.org. تمام قالب‌های فایلی که توسط Pillow (PIL) پشتیبانی می‌شوند، قابل استفاده هستند.

این فیلتر باید اولین فیلتر در یک زنجیره از فیلترها باشد، زیرا داده‌های دودویی را دریافت کرده و داده‌های متنی را خروجی می‌دهد.

url: https://example.net/ocr-test.png
filter:
  - ocr:
      timeout: 5
      language: eng
  - strip

زیرفیلترهای timeout و language اختیاری هستند:

  • timeout: مهلت زمانی برای تشخیص، به ثانیه (پیش‌فرض: 10 ثانیه)
  • language: زبان متن (مانند fra یا eng+fra، پیش‌فرض: eng)

فیلتر jq از بایندرهای پایتون برای jq https://stedolan.github.io/jq/ استفاده می‌کند که یک پردازشگر سبک JSON است. استفاده از این فیلتر مستلزم نصب ماژول پایتون اختیاری jq https://github.com/mwilliamson/jq.py است.

url: https://example.net/jobs.json
filter:
   - jq:
      query: '.[].title'

زیرفیلتر query اختیاری است:

•
query: یک رشته فیلتر معتبر jq.

از تجمیع‌ها، انتخاب‌ها و عملگرهای توکار مانند length پشتیبانی می‌کند. برای اطلاعات بیشتر در مورد عملیات‌های مجاز، به راهنمای jq https://stedolan.github.io/jq/manual/ مراجعه کنید.

$XDG_CONFIG_HOME/urlwatch/urls.yaml

urlwatch(1), urlwatch-intro(5), urlwatch-jobs(5)

2024 Thomas Perl

28 اکتبر 2024 urlwatch