bytebuster: (IT Crowd Jen)
[personal profile] bytebuster
Ура, %SUBJ%, котани! Налітай!

Скрипт працює так:

  1. Додає от такий лінк на сторінку допису:
  2. По кліку на посилання відкриває http://www.dreamwidth.org/entry/new у новому вікні (target="_blank") та заповнює два поля: Subject та Body.


Known Bugs:

  • Не вставляється YouTube відео. Спробую побороти, але там багато возні. — Починив у v.0.3
  • Не розгортаються Cut Tags. Перед перепостом треба все руками розгортати
  • З тієї ж причини, Cut Tags у перепощеному дописі не вставляються. Їх треба прописувати руками.
  • Глючить, якщо пост містить <lj user="..."> — ім'я цього юзера помилково вставляється у шапку перепосту (замість імені того юзера, чий пост ви перепощуєте). — Починив у v.0.2

Зауваження:

  • Перше і найголовніше: Ніколи не встановлюйте скрипти від невідомих джерел!
    Особливо якщо ви не розумієте код.
  • Tags та To [Journal/Community] не прописує. Можливо, потім придумаю шаблони для перепостів, але поки що цього нема. Все как у дідов жежешечки, світла їй пам'ять.
  • Перевіряв на сторінках індивідуальних журналів (http://bytebuster.dreamwidth.org/), комун (http://bitter-onion.dreamwidth.org/) та індивідуальних дописів (http://bitter-onion.dreamwidth.org/1139072.html).
  • Перевіряв лише на Firefox. У кого Chrome, перевірте хто-небудь на Tampermonkey, га? Я не упевнений, що там працюють функції, специфічні для GM.
  • Багрепорти приймаються, але я не глибоко дружу з JavaScript, тому не гарантія, що я зможу вилікувати усі можливі проблеми.

Встановлення

  • Ставимо собі Greasemonkey;
  • Перезапускаємо Firefox;
  • Повертаємося до цього допису, виділяємо все тіло скрипта і копіюємо до Clipboard;
  • Тиць в кнопку Greasemonkey на Toolbar, тиць New User Script…;
  • У новому віконці внизу кнопка Use Script from Clipboard;
  • Налаштувати свої шаблони у секції:
    // **** SETTINGS ****************************************************
  • Зберегти;
  • Відкрити будь-яку сторінку на DreamWidth.
Сам скрипт залитий на BitBucket (завжди нова версія), а також (увага, стара версія!) під катом:

// ==UserScript==
// @name        DreamWidth Reposter
// @namespace   bytebuster.dreamwidth.org
// @description Adds LJ-like Repost functionality for DreamWidth
// @include     http://*.dreamwidth.org/*
// @exclude     http://*.dreamwidth.org/profile*
// @exclude     http://*.dreamwidth.org/calendar*
// @exclude     http://*.dreamwidth.org/tag/
// @version     0.3
// @grant       GM_log
// @grant       GM_getValue
// @grant       GM_setValue
// @grant       GM_deleteValue
// ==/UserScript==

/* **********************************************************************************

    This script has two main functions:
    * addRepostLinks - triggers on all DreamWidth pages; adds "Repost" links to entries;
    * populatePostForm - triggers on /entry/new page; fills up the "Post Entry" fields

    Цей скрипт містить дві основні функції:
    * addRepostLinks - запускається на усіх сторінках DreamWidth pages; додає кнопку «Перепостити»;
    * populatePostForm - запускається на сторінці /entry/new page; заповнює поля вводу

********************************************************************************** */

/*
 * 0.3 fixed applied domain and URL;
       fixed Youtube video embed
       minor fix if mistakenly decided that post in community,
         while it actually is in user's own journal
 * 0.2 added group/blog references
       fix bug on other users references
 * 0.1 Initial reease
*/

(function(){
  // **** SETTINGS ****************************************************
  // Main settings
  // Головні налаштування
  const REPOST_TEXT = "Перепостити"; // Так виглядатиме текст кнопки «Репост»
  const REPOST_TEMPLATE = 'Перепост допису <lj user="{poster}">: <a href="{link}">{subj}</a>\n{body}';
  const REPOST_TEMPLATE_COMMUNITY = 'Перепост допису <lj user="{poster}"> @ <lj user="{community}">: <a href="{link}">{subj}</a>\n{body}';
  const DEBUG = false;

  // **** CONSTANTS ***************************************************
  // You don't need it unless DreamWidth changes its classes (impossible, yeah)
  // Вам тут не треба нічого міняти, допоки Дрім не поміняє імена класів (майже нереально)

  const CLS_ENTRY_TITLE   = "entry-title";
  const CLS_ENTRY_WRAPPER = "entry-wrapper";
  const CLS_ENTRY_POSTER  = "entry-poster";
  const CLS_LJUSER        = "ljuser";
  const ATTR_LJUSER       = "lj:user";
  const CLS_ENTRY_CONTENT = "entry-content";
  const CLS_ENTRY_LINKS   = "entry-interaction-links";
  const ID_INPUT_SUBJECT  = "id-subject-0";
  const ID_INPUT_BODY     = "id-event-1";
  const CLS_EMBED         = "lj_embedcontent-wrapper";

  const POST_URL = "http://www.dreamwidth.org/update";
  const POST_URL2 = "/entry/new";
  const REPOST_PARAM="repost";
  const CONTENT_DEFAULT = "";
  const CONTENT_TAG = "DW_REPOST_CONTENT"; // how we save the reposted entry in GM_setValue

  const REGEX_YOUTUBE_LINK     =  /^.*(?:youtu\.be\/|v\/|u\/\w\/|embed\/|watch\?v=|\&v=)([^#\&\?]*).*/gmi; // /www.youtube.com\/watch?v=(.+?)/gmi;
  const EMBED_YOUTUBE_TEMPLATE = '<iframe width="640" height="360" src="https://www.youtube.com/embed/{videoID}" frameborder="0" allowfullscreen></iframe>';

// applies a parser on strings and log error if failed
function parse(parser, where, description) {
  var ret;
  match = parser.exec(where);
  if( match === null ) {
    GM_log("Failed to parse " + description + " from text: " + where);
    ret = "(null)";
  } else {
    ret = match[1];
  }
  return ret;
}

function DebugMessage( what ) {
  if(DEBUG) { GM_log(what); }
}

// checks for URL parameter
function getQueryVariable(variable) {
  var query = window.location.search.substring(1);
  var vars = query.split("&");
  for (var i=0;i<vars.length;i++) {
    var pair = vars[i].split("=");
    if (pair[0] == variable) {
      return pair[1];
    }
  }
  DebugMessage('Query Variable ' + variable + ' not found');
}

// Adds Repost links to all entries on the page
// Додає посилання «Перепост» внизу усіх дописів на сторінці
function addRepostLinks() {
  DebugMessage("Adding Repost links begin...");
  var entries = document.getElementsByClassName(CLS_ENTRY_WRAPPER);

  for (var entry_index=0; entry_index<entries.length; entry_index++) {
    addRepostLink(entries[entry_index]);
  }
  DebugMessage("Adding Repost links end");
}

// Gets the saved content for repost
function getRepostData() {
  DebugMessage("getRepostData begin");

  return GM_getValue(CONTENT_TAG, CONTENT_DEFAULT);
}
// Sets the content for repost
function setRepostData(repostData) {
  DebugMessage("setRepostData begin " + repostData);
  // delete the state if it is the default
  if( repostData == CONTENT_DEFAULT ) {
    GM_deleteValue(CONTENT_TAG);
  } else {
    // set the state otherwise
    GM_setValue(CONTENT_TAG, repostData);
  }
  DebugMessage("setRepostData end");
}

// Saves JSON data from the reposted entry
// Зберігає допис і його шапку
function rememberPost(elEntry) {
  var elPoster, elLjuser, elTitle, elContent; // elements
  var entryPoster, entryCommunity, entryLink, entrySubject, entryBody, subdomain; // strings
  var repostData; // JSON object
  DebugMessage("rememberPost begin");

  subdomain = window.location.host.split(".")[0];
  // get Poster userId
  elPoster = elEntry.getElementsByClassName(CLS_ENTRY_POSTER)[0];

  if(elPoster && elPoster.hasChildNodes()) {
    // we seem to be in a community, parse out poster name from attribute
    elLjuser = elPoster.getElementsByClassName(CLS_LJUSER)[0];
    entryPoster = elLjuser.getAttribute(ATTR_LJUSER);
    entryCommunity = subdomain;
  } else {
    // we seem to be in a journal, parse out poster name from URL (FIXME)
    entryPoster = subdomain;
    entryCommunity = "";
  }
  // Quick fix: fix if we mistakenly set community
  if(entryPoster == entryCommunity) {
    entryCommunity = "";
  }

  // get Subj and Link
  elTitle = elEntry.getElementsByClassName(CLS_ENTRY_TITLE)[0];
  entryLink    = elTitle.getElementsByTagName("a")[0].href;
  entrySubject = elTitle.textContent;

  // get Body
  elContent = elEntry.getElementsByClassName(CLS_ENTRY_CONTENT)[0]
    .cloneNode(true);

  // Apply fixes
  elContent = FixYoutube(elContent);
  elContent = FixUsers(elContent);

  entryBody = elContent.innerHTML;

  repostData =
    JSON.stringify(
      {
        "link"      : entryLink,
        "poster"    : entryPoster,
        "community" : entryCommunity,
        "subj"      : entrySubject,
        "body"      : entryBody
      }
    );

  DebugMessage("Saving JSON: " + repostData);
  setRepostData(repostData);
  DebugMessage("rememberPost end");
}

// Fixes User references
// Takes a cloned node to fix
// Returns it as well
function FixUsers(element) {
  var embeds; // list of embed objects

  DebugMessage("FixUsers begin");

  embeds = element.getElementsByClassName(CLS_LJUSER);

  for (var embed_index=0; embed_index<embeds.length; embed_index++) {
    var elLjuser, elLjUser2; // elements
    var userName; // strings

    elLjuser = embeds[embed_index];
    if(elLjuser.nodeName != "SPAN") { DebugMessage("Element frame does not look like a user reference, exiting"); continue; }

    userName = elLjuser.getAttribute(ATTR_LJUSER);

    // creating an HTML fragment to replace the broken link
    elLjUser2 = document.createElement("lj");
    elLjUser2.setAttribute("user", userName);

    // replacing the element
    element.replaceChild(elLjUser2, elLjuser)
    embed_index--;
  }
  DebugMessage("FixUsers end");
  return element;
}

// Fixes YouTube links
// Takes a cloned node to fix
// Returns it as well
function FixYoutube(element) {
  var embeds; // list of embed objects

  DebugMessage("FixYoutube begin");

  embeds = element.getElementsByClassName(CLS_EMBED);

  for (var embed_index=0; embed_index<embeds.length; embed_index++) {
    var elFrame, elLinkDiv, elLink, elRange, elFragment, elFirstNode; // elements
    var linkAddress, linkBodyNew; // strings

    elFrame = embeds[embed_index];
    if(elFrame.nodeName != "DIV") { DebugMessage("Element frame does not look like a YouTube, exiting"); continue; }

    elLinkDiv = elFrame.nextSibling;
    if(elLinkDiv === null) { DebugMessage("Failed to find YouTube link DIV, exiting"); continue; }

    elLink = elLinkDiv.getElementsByTagName("a")[0];
    if(elLink === null) { DebugMessage("YouTube link seems to be broken, exiting"); continue; }

    linkAddress = parse(REGEX_YOUTUBE_LINK, elLink.href, "YouTube Link");
    linkBodyNew = EMBED_YOUTUBE_TEMPLATE
      .replace("{videoID}", linkAddress);

    // creating an HTML fragment to replace the broken link
    elRange = document.createRange();
    elRange.selectNode(document.body); // required in Safari
    elFragment = elRange.createContextualFragment(linkBodyNew);
    elFirstNode = elFragment.firstChild;

    // replacing the element
    element.removeChild(elFrame);
    element.replaceChild(elFirstNode, elLinkDiv)
    embed_index--;
  }
  DebugMessage("FixYoutube end");
  return element;
}

// Adds Repost links to one entry
// Додає посилання «Перепост» внизу допису
function addRepostLink(entry) {
  var elFooter, elRepostLink, elRepostLinkLI; // elements
  var entryTitle, entryLink, userName, entryId;

  // check if entry is a DOM element
  if( !entry.tagName ) { return; }

  elFooter = entry.getElementsByClassName(CLS_ENTRY_LINKS)[0];
  // must be < ul >

  elRepostLink = document.createElement("a");
  elRepostLink.href = POST_URL + "?" + REPOST_PARAM +"=1";
  elRepostLink.target = "_blank";
  elRepostLink.addEventListener('click', function(event) { rememberPost(entry); /*event.stopPropagation(); event.preventDefault();*/ }, true);
  elRepostLink.text = REPOST_TEXT;
  elRepostLinkLI = document.createElement("li");
  elRepostLinkLI.appendChild(elRepostLink);
  elFooter.appendChild(elRepostLinkLI);
}

// Fills up the "Post Entry" form
// Заповнює форму «Створити допис»
function populatePostForm() {
  DebugMessage("Populate Post begin");

  var repostedUrl = getQueryVariable(REPOST_PARAM);
  if(! repostedUrl) {
    DebugMessage("Does not look like a repost, exiting");
    return;
  }

  // continue

  var repostDataString, repostData; // JSON data
  var postBody; // strings
  var elSubject, elBody; // elements

  repostDataString = getRepostData();
  DebugMessage("Repost data=" + repostDataString);

  repostData = JSON.parse(repostDataString);
  DebugMessage("Repost data parsed=" + JSON.stringify(repostData));

  DebugMessage("Preparing postBody...");
  postBody =
    ((repostData.community == "") ? REPOST_TEMPLATE : REPOST_TEMPLATE_COMMUNITY)
    .replace('{poster}', repostData.poster)
    .replace('{community}', repostData.community)
    .replace('{link}', repostData.link)
    .replace('{subj}', repostData.subj)
    .replace('{body}', repostData.body)
  ;

  DebugMessage("postBody=" + postBody);

  elBody = document.getElementById(ID_INPUT_BODY);
  DebugMessage("elBody was: " + elBody.value);
  elBody.value = postBody;
  DebugMessage("elBody became: " + elBody.value);

  elSubject = document.getElementById(ID_INPUT_SUBJECT);
  DebugMessage("elSubject was: " + elSubject.value);
  elSubject.value = repostData.subj;
  DebugMessage("elSubject became: " + elSubject.value);
  setRepostData(CONTENT_DEFAULT);
  DebugMessage("Populate Post end");
}

  var thisUrl = window.location.href;
  if(thisUrl.indexOf(POST_URL2) != -1) {
    populatePostForm();
  } else {
    addRepostLinks();
  }
})();

...

Дата: П'ятниця, 30 Грудень 2016 03:48 (UTC)
henry_flower: A melancholy wolf (Default)
Від: [personal profile] henry_flower
навряд--dw вирізає iframes перед тим як рендерити коментар.

але можна запостити линк з img з 1м фреймом, себто юзер кликне на картинці і перейде до ютуба.

напр., відео https://www.youtube.com/watch?v=yKnIhCmPycw

його 1й фрейм http://img.youtube.com/vi/yKnIhCmPycw/0.jpg

у коментарі пишемо

<a href="https://www.youtube.com/watch?v=yKnIhCmPycw" target="_blank">
<img src="http://img.youtube.com/vi/yKnIhCmPycw/0.jpg">
</a>


результат:



...

Дата: П'ятниця, 30 Грудень 2016 10:16 (UTC)
gourakov: (Default)
Від: [personal profile] gourakov
Великолепное решение!
Спасибо за совет!
Извините за мою непонятливость, - а где и как найти ссылку на готовый первый фрейм видео?
Заранее благодарен!
Сейчас ссылку на первый фрейм составил вручную.








...

Дата: П'ятниця, 30 Грудень 2016 10:19 (UTC)
gourakov: (Default)
Від: [personal profile] gourakov
Вроде получилось, но уж очень это много времени заняло с непривычки ))
Еще раз благодарю!

...

Дата: П'ятниця, 30 Грудень 2016 10:31 (UTC)
gourakov: (Default)
Від: [personal profile] gourakov
Для закрепления полученных знаний ))





С наступающим Новым годом!
Сторінку створено Понеділок, 26 Червень 2017 23:59

Червень 2017

П В С Ч П С Н
    1 2 3 4
5 6 7 8 9 10 11
12 13 14 15 16 17 18
19 20 21 22 23 24 25
2627282930  
Створено з Dreamwidth Studios

За стиль дякувати