[gelöst] NewsFeed-Einträge aus anderen Feeds zusammenführen
am 21.10.2008 - 15:17 Uhr in
Ich nutze die NewsFeeds um verschiedene Feeds von anderen Seiten zusammenzuführen. Auf einigen Seiten sind die Nachrichten mit unterschiedlicher bzw. individueller Lebensdauer versehen, d. h. eine Nachricht kann durchaus nur eine Stunde relevant sein andere sollen über Wochen angezeigt werden. Prinzipiell möchte ich also eine Spiegelung verschiedener Feeds.
Wie bekomme ich das so hin, das nur Nachrichten angezeigt werden die auch noch auf dem Ursprungssystem vorhanden sind? Stelle ich den Punkt "Verwerfe Einträge, die älter sind als:" kurz ein, werden mir die aktuellen Nachrichten die ein älteres Erstellungsdatum haben auch nicht mehr angezeigt. Stelle ich die Zeit höher ein, werden mir noch Nachrichten angezeigt die nicht mehr aktuell sind.
Gruß
UwBach
- Anmelden oder Registrieren um Kommentare zu schreiben
Hallo. Ich war bisher der
am 22.10.2008 - 01:54 Uhr
Hallo.
Ich war bisher der Meinung, dass dies bei einer Aktualisierung des Feeds automatisch geschieht, dass im Origial Feed gelöschte Objekte auch vom Feed-Aggregator gelöscht werden.
Falls dies nicht so ist, bin ich ebenfalls an einer Lösung interessiert.
Gruß
JThan
_____
--> http://www.drupalcenter.de/showroom/11994 <--
Alle Angaben in meinen Beiträgen sind stets ohne Gewähr und auf eigenes Risiko für bare Münze zu nehmen.
Feeds werden automatisch aktualisiert aber nicht gelöscht
am 22.10.2008 - 07:19 Uhr
In Drupal (Aggregator-Modul) stellst du die "Lebensdauer" der einzelnen Beiträge ein und die Beiträge bleiben so lange in der DB. Ist ja auch normalerweise sinnvoll, da sich die Feeds auf Artikel beziehen die länger Bestand haben.
Das Aggregator-Modul holt sich also die einzelnen Meldungen, prüft ob diese schon in Datenbank sind (erst eine ID, dann die URL und schließlich den Titel) und fügt neue Meldungen hinzu. Dann überprüft es ob die Meldungen die "Lebensdauer" überschritten haben und löscht die zu alten Beiträge. Dabei werden auch neue Beiträge gelöscht die ein zu altes Erstellungsdatum (z. B.
<dc:date>
) haben - sehr unangenehm.Eine Überprüfung ob ein Feed noch vorhanden ist findet leider nicht statt. Das hat zur Folge, dass Beiträge in den Feeds auf Beiträge verweisen können die auf dem Ursprungssystem nicht mehr existieren.
Ich arbeite grade an einer Übergangslösung - scheinbar gibt es noch keine Drupal-Lösung. Die teile ich dir dann gerne mit.
Gruß
UwBach
Doch Drupal loggt es, wenn
am 22.10.2008 - 09:32 Uhr
Doch Drupal loggt es, wenn ein Feed nicht mehr funkz.(URL falsch etc.) Bzw. bei einem manuellen Abrufen eines Feeds wird ggf. auch eine Warnmeldung ausgegeben.
----------------------------------------
Alle Angaben ohne Gewähr!!:D
http://www.tobiasbaehr.de/
Leider funktioniert das nur, wenn ..
am 22.10.2008 - 09:40 Uhr
.. die Seite gar nicht zu erreichen ist oder einen entsprechenden Fehlercode zurückgibt. Die Meldungen beziehen sich dann auch auf den gesamten Feed und nicht auf einzelne Nachrichten des Feeds.
Mir geht es aber um die einzelnen Nachrichten eines Feeds. Die werden nicht mehr überprüft, wenn der Feed grundsätzlich läuft. Hast du evtl. hierfür eine Lösung?
Gruß
UwBach
Hi @JThan
am 22.10.2008 - 11:00 Uhr
Ich war bisher der Meinung, dass dies bei einer Aktualisierung des Feeds automatisch geschieht, dass im Origial Feed gelöschte Objekte auch vom Feed-Aggregator gelöscht werden.
Falls dies nicht so ist, bin ich ebenfalls an einer Lösung interessiert.
Hier sind zwei Lösungen - eine Holzhammer und eine etwas elegantere. Leider mußte ich dazu in das Aggregator-Modul eingreifen, etwas was ich sonst immer ablehne. Aber beide Versionen beziehen sich auf die Funktion "aggregator_parse_feed(&$data, $feed)" in /module/aggregator/aggregator.module. Das bedingt nach jedem Update den Code wieder anzufassen.
Die erste Lösung löscht einfach alle Einträge aus dem Feed und schreibt dann wieder die neuen hinein. Das würde ich nur für Feeds anwenden die nicht viele Inhalte haben. Einfach - brutal - schnell.
// Wenn kein Fehler aufgetreten ist
else
{
// Feeds definieren die geprüft werden sollen
if($feed['fid'] == 4)
{
db_query('DELETE FROM {aggregator_item} WHERE fid = %d ', $feed['fid']);
db_query('DELETE FROM {aggregator_category_item} WHERE iid NOT IN (SELECT iid FROM {aggregator_item})');
watchdog('aggregator', t('Die Nachrichten von %site wurden vollständig erneuert.', array('%site' => $feed['title']), WATCHDOG_WARNING));
}
}
Schau am besten unten nach wo die eingefügt werden muss. Ist unten allerdings auskommentiert.
Die andere Lösung ist etwas aufwändiger - schaue nach "// NEU START ". Zusätzliche Funktionen die Feeds unterstützen sind hier jetzt nicht berücksichtigt.
/**
* Parse a feed and store its items.
*
* @param $data
* The feed data.
* @param $feed
* An associative array describing the feed to be parsed.
* @return
* 0 on error, 1 otherwise.
*/
function aggregator_parse_feed(&$data, $feed) {
global $items, $image, $channel;
// Unset the global variables before we use them:
unset($GLOBALS['element'], $GLOBALS['item'], $GLOBALS['tag']);
$items = array();
$image = array();
$channel = array();
// parse the data:
$xml_parser = drupal_xml_parser_create($data);
xml_set_element_handler($xml_parser, 'aggregator_element_start', 'aggregator_element_end');
xml_set_character_data_handler($xml_parser, 'aggregator_element_data');
if (!xml_parse($xml_parser, $data, 1)) {
watchdog('aggregator', 'The feed from %site seems to be broken, due to an error "%error" on line %line.', array('%site' => $feed['title'], '%error' => xml_error_string(xml_get_error_code($xml_parser)), '%line' => xml_get_current_line_number($xml_parser)), WATCHDOG_WARNING);
drupal_set_message(t('The feed from %site seems to be broken, because of error "%error" on line %line.', array('%site' => $feed['title'], '%error' => xml_error_string(xml_get_error_code($xml_parser)), '%line' => xml_get_current_line_number($xml_parser))), 'error');
return 0;
}
/*
/// NEU START
// Wenn kein Fehler aufgetreten ist
else
{
// Feeds definieren die geprüft werden sollen
if($feed['fid'] == 4)
{
db_query('DELETE FROM {aggregator_item} WHERE fid = %d ', $feed['fid']);
db_query('DELETE FROM {aggregator_category_item} WHERE iid NOT IN (SELECT iid FROM {aggregator_item})');
watchdog('aggregator', t('Die Nachrichten von %site wurden vollständig erneuert.', array('%site' => $feed['title']), WATCHDOG_WARNING));
}
}
/// NEU ENDE
*/
xml_parser_free($xml_parser);
// We reverse the array such that we store the first item last, and the last
// item first. In the database, the newest item should be at the top.
$items = array_reverse($items);
// Initialize variables.
$title = $link = $author = $description = $guid = NULL;
// NEU START
// Gibt an welche Feeds auf Alteinträge überprüft werden sollen
// Key = fid (Feed-ID) -- Wert = True/False
// Beliebig erweiterbar
$betroffene_feed = array(1 => 0, 2 => 0, 3 => 0, 4 => 1, 6 => 0);
if($betroffene_feed[$feed['fid']])
$alteintrag[$feed['fid']]['max'] = db_result(db_query('SELECT MAX(iid) FROM {aggregator_item} WHERE fid = %d', $feed['fid']));
// NEU ENDE
foreach ($items as $item) {
unset($title, $link, $author, $description, $guid);
// Prepare the item:
foreach ($item as $key => $value) {
$item[$key] = trim($value);
}
// Resolve the item's title. If no title is found, we use up to 40
// characters of the description ending at a word boundary but not
// splitting potential entities.
if (!empty($item['TITLE'])) {
$title = $item['TITLE'];
}
elseif (!empty($item['DESCRIPTION'])) {
$title = preg_replace('/^(.*)[^\w;&].*?$/', "\\1", truncate_utf8($item['DESCRIPTION'], 40));
}
else {
$title = '';
}
// Resolve the items link.
if (!empty($item['LINK'])) {
$link = $item['LINK'];
}
else {
$link = $feed['link'];
}
$guid = isset($item['GUID']) ? $item['GUID'] : '';
// Atom feeds have a CONTENT and/or SUMMARY tag instead of a DESCRIPTION tag.
if (!empty($item['CONTENT:ENCODED'])) {
$item['DESCRIPTION'] = $item['CONTENT:ENCODED'];
}
else if (!empty($item['SUMMARY'])) {
$item['DESCRIPTION'] = $item['SUMMARY'];
}
else if (!empty($item['CONTENT'])) {
$item['DESCRIPTION'] = $item['CONTENT'];
}
// Try to resolve and parse the item's publication date. If no date is
// found, we use the current date instead.
$date = 'now';
foreach (array('PUBDATE', 'DC:DATE', 'DCTERMS:ISSUED', 'DCTERMS:CREATED', 'DCTERMS:MODIFIED', 'ISSUED', 'CREATED', 'MODIFIED', 'PUBLISHED', 'UPDATED') as $key) {
if (!empty($item[$key])) {
$date = $item[$key];
break;
}
}
$timestamp = strtotime($date); // As of PHP 5.1.0, strtotime returns FALSE on failure instead of -1.
if ($timestamp <= 0) {
$timestamp = aggregator_parse_w3cdtf($date); // Returns FALSE on failure
if (!$timestamp) {
$timestamp = time(); // better than nothing
}
}
// Save this item. Try to avoid duplicate entries as much as possible. If
// we find a duplicate entry, we resolve it and pass along its ID is such
// that we can update it if needed.
if (!empty($guid)) {
$entry = db_fetch_object(db_query("SELECT iid FROM {aggregator_item} WHERE fid = %d AND guid = '%s'", $feed['fid'], $guid));
}
else if ($link && $link != $feed['link'] && $link != $feed['url']) {
$entry = db_fetch_object(db_query("SELECT iid FROM {aggregator_item} WHERE fid = %d AND link = '%s'", $feed['fid'], $link));
}
else {
$entry = db_fetch_object(db_query("SELECT iid FROM {aggregator_item} WHERE fid = %d AND title = '%s'", $feed['fid'], $title));
}
$item += array('AUTHOR' => '', 'DESCRIPTION' => '');
aggregator_save_item(array('iid' => (isset($entry->iid) ? $entry->iid: ''), 'fid' => $feed['fid'], 'timestamp' => $timestamp, 'title' => $title, 'link' => $link, 'author' => $item['AUTHOR'], 'description' => $item['DESCRIPTION'], 'guid' => $guid));
// NEU START
// Prüfen ob ein Feed betroffen ist
// Prüfen ob eine iid übergeben wurde
// wurde die iid nicht gefunden ist der Eintrag nicht mehr vorhanden bzw. neu eingetragen - dann löschen
if($betroffene_feed[$feed['fid']] and isset($entry->iid))
$alteintrag[$feed['fid']]['iid'][] = $entry->iid;
// NEU ENDE
}
// NEU START
// löschen der nicht mehr benötigten Einträge
// nur notwendig wenn fid eingetragen
if(count($alteintrag))
{
foreach($alteintrag as $fid => $werte)
{
if(!$werte['max'])
break;
else
{
// Ermitteln welcher Feed betroffen ist und welches der letzte bekannte Eintrag war
// Welche Einträge nicht glöscht werden sollen
// Hau weg den alten Kram
db_query('DELETE FROM {aggregator_item} WHERE fid = '.$fid.' AND iid <= '.$werte['max'].' AND iid NOT IN ('.implode(', ', $werte['iid']).')');
// Bereinigen der Tabelle aggregator_category_item
db_query('DELETE FROM {aggregator_category_item} WHERE iid NOT IN (SELECT iid FROM {aggregator_item})');
}
}
}
// NEU ENDE
// Remove all items that are older than flush item timer.
$age = time() - variable_get('aggregator_clear', 9676800);
$result = db_query('SELECT iid FROM {aggregator_item} WHERE fid = %d AND timestamp < %d', $feed['fid'], $age);
$items = array();
$num_rows = FALSE;
while ($item = db_fetch_object($result)) {
$items[] = $item->iid;
$num_rows = TRUE;
}
if ($num_rows) {
db_query('DELETE FROM {aggregator_category_item} WHERE iid IN ('. implode(', ', $items) .')');
db_query('DELETE FROM {aggregator_item} WHERE fid = %d AND timestamp < %d', $feed['fid'], $age);
}
return 1;
}
In meinen Anwendungen läuft die aufwändigere Version problemlos (soweit ich das nach ca. 100 Nachrichten sagen kann).
Gruß
UwBach